Compare commits
33 Commits
v2.1.34
...
v2.1.36-be
Author | SHA1 | Date | |
---|---|---|---|
![]() |
27d2c7b078 | ||
![]() |
2fb12ccf65 | ||
![]() |
cb92d159c1 | ||
![]() |
64bdf4237c | ||
![]() |
fd7b4ec7e3 | ||
![]() |
57eb57d4d7 | ||
![]() |
7974e9505b | ||
![]() |
7498fb37b5 | ||
![]() |
2cc3e88e6c | ||
![]() |
5fd8cfeb80 | ||
![]() |
b295566a4e | ||
![]() |
e0943a2d55 | ||
![]() |
3015740c3e | ||
![]() |
ec9ff2f803 | ||
![]() |
ec8aae9122 | ||
![]() |
52e608cc43 | ||
![]() |
8213f270e5 | ||
![]() |
7085042b0d | ||
![]() |
6a411d2458 | ||
![]() |
38e2fbabb8 | ||
![]() |
85709f754a | ||
![]() |
623a1e8a91 | ||
![]() |
de69945ebe | ||
![]() |
7095fa6ac6 | ||
![]() |
a59e8298fd | ||
![]() |
2737d52279 | ||
![]() |
0ac1ad4386 | ||
![]() |
2db328ac31 | ||
![]() |
b6de4ad054 | ||
![]() |
cfea7164b7 | ||
![]() |
7e7e5a6be4 | ||
![]() |
df57f4c009 | ||
![]() |
c2185c4ce5 |
10
API.md
10
API.md
@@ -416,6 +416,7 @@ Returns:
|
||||
"Drama",
|
||||
"Fantasy"
|
||||
],
|
||||
"grandparent_guid": "com.plexapp.agents.thetvdb://121361?lang=en",
|
||||
"grandparent_rating_key": "1219",
|
||||
"grandparent_thumb": "/library/metadata/1219/thumb/1503306930",
|
||||
"grandparent_title": "Game of Thrones",
|
||||
@@ -443,6 +444,7 @@ Returns:
|
||||
"optimized_version_title": "",
|
||||
"originally_available_at": "2016-04-24",
|
||||
"original_title": "",
|
||||
"parent_guid": "com.plexapp.agents.thetvdb://121361/6?lang=en",
|
||||
"parent_media_index": "6",
|
||||
"parent_rating_key": "153036",
|
||||
"parent_thumb": "/library/metadata/153036/thumb/1503889210",
|
||||
@@ -507,7 +509,9 @@ Returns:
|
||||
"stream_video_language": "",
|
||||
"stream_video_language_code": "",
|
||||
"stream_video_ref_frames": "4",
|
||||
"stream_video_full_resolution": "1080p",
|
||||
"stream_video_resolution": "1080",
|
||||
"stream_video_scan_type": "progressive",
|
||||
"stream_video_width": "1920",
|
||||
"studio": "HBO",
|
||||
"subtitle_codec": "",
|
||||
@@ -560,12 +564,14 @@ Returns:
|
||||
"video_decision": "direct play",
|
||||
"video_frame_rate": "23.976",
|
||||
"video_framerate": "24p",
|
||||
"video_full_resolution": "1080p",
|
||||
"video_height": "1078",
|
||||
"video_language": "",
|
||||
"video_language_code": "",
|
||||
"video_profile": "high",
|
||||
"video_ref_frames": "4",
|
||||
"video_resolution": "1080",
|
||||
"video_scan_type": "progressive",
|
||||
"video_width": "1920",
|
||||
"view_offset": "1000",
|
||||
"width": "1920",
|
||||
@@ -1110,6 +1116,7 @@ Returns:
|
||||
"Drama",
|
||||
"Fantasy"
|
||||
],
|
||||
"grandparent_guid": "com.plexapp.agents.thetvdb://121361?lang=en",
|
||||
"grandparent_rating_key": "1219",
|
||||
"grandparent_thumb": "/library/metadata/1219/thumb/1462175063",
|
||||
"grandparent_title": "Game of Thrones",
|
||||
@@ -1150,6 +1157,7 @@ Returns:
|
||||
"video_language_code": "",
|
||||
"video_profile": "high",
|
||||
"video_ref_frames": "4",
|
||||
"video_scan_type": "progressive",
|
||||
"video_width": "1920",
|
||||
"selected": 0
|
||||
},
|
||||
@@ -1184,6 +1192,7 @@ Returns:
|
||||
],
|
||||
"video_codec": "h264",
|
||||
"video_framerate": "24p",
|
||||
"video_full_resolution": "1080p",
|
||||
"video_profile": "high",
|
||||
"video_resolution": "1080",
|
||||
"width": "1920"
|
||||
@@ -1192,6 +1201,7 @@ Returns:
|
||||
"media_type": "episode",
|
||||
"original_title": "",
|
||||
"originally_available_at": "2016-04-24",
|
||||
"parent_guid": "com.plexapp.agents.thetvdb://121361/6?lang=en",
|
||||
"parent_media_index": "6",
|
||||
"parent_rating_key": "153036",
|
||||
"parent_thumb": "/library/metadata/153036/thumb/1462175062",
|
||||
|
30
CHANGELOG.md
30
CHANGELOG.md
@@ -1,5 +1,35 @@
|
||||
# Changelog
|
||||
|
||||
## v2.1.36-beta (2019-10-05)
|
||||
|
||||
* Monitoring:
|
||||
* Fix: Activity card title not updating after pre-rolls or auto-play.
|
||||
* History:
|
||||
* Fix: Display correct interlaced or progressive video scan type on stream data modal.
|
||||
* Graphs:
|
||||
* New: Separate interlaced and progressive video scan type on source and stream resolution graphs.
|
||||
* API:
|
||||
* New: Added parent_guid and grandparent_guid to get_activity and get_metadata commands.
|
||||
|
||||
|
||||
## v2.1.35-beta (2019-09-24)
|
||||
|
||||
* Monitoring:
|
||||
* Fix: Audio shown as blank on activity cards when changing audio tracks during direct play.
|
||||
* Fix: Display correct interlaced or progressive video scan type on activity cards.
|
||||
* New: Added flag for Nvidia hardware decoding on activity cards.
|
||||
* Notifications:
|
||||
* Fix: Notification parameter prefix and suffix were not substituted correctly.
|
||||
* Fix: Release Date notification parameter was incorrectly casted to an integer instead of a string.
|
||||
* New: Added video scan type and full resolution notification parameters.
|
||||
* UI:
|
||||
* Fix: Movies with the same title but different year being grouped on the homepage stats cards.
|
||||
* API:
|
||||
* New: Added video scan type and full resolution values to get_activity command.
|
||||
* Other:
|
||||
* Fix: Tautulli logging out every time after saving settings and restarting.
|
||||
|
||||
|
||||
## v2.1.34 (2019-09-03)
|
||||
|
||||
* History:
|
||||
|
@@ -232,11 +232,11 @@ DOCUMENTATION :: END
|
||||
hw_d = ' (HW)' if data['transcode_hw_decoding'] else ''
|
||||
hw_e = ' (HW)' if data['transcode_hw_encoding'] else ''
|
||||
%>
|
||||
Transcode (${data['video_codec'].upper()}${hw_d} ${VIDEO_RESOLUTION_OVERRIDES.get(data['video_resolution'], data['video_resolution'])} <i class="fa fa-long-arrow-right"></i> ${data['stream_video_codec'].upper()}${hw_e} ${VIDEO_RESOLUTION_OVERRIDES.get(data['stream_video_resolution'], data['stream_video_resolution'])})
|
||||
Transcode (${data['video_codec'].upper()}${hw_d} ${data['video_full_resolution']} <i class="fa fa-long-arrow-right"></i> ${data['stream_video_codec'].upper()}${hw_e} ${data['stream_video_full_resolution']})
|
||||
% elif data['stream_video_decision'] == 'copy':
|
||||
Direct Stream (${data['stream_video_codec'].upper()} ${VIDEO_RESOLUTION_OVERRIDES.get(data['stream_video_resolution'], data['stream_video_resolution'])})
|
||||
Direct Stream (${data['stream_video_codec'].upper()} ${data['stream_video_full_resolution']})
|
||||
% else:
|
||||
Direct Play (${data['stream_video_codec'].upper()} ${VIDEO_RESOLUTION_OVERRIDES.get(data['stream_video_resolution'], data['stream_video_resolution'])})
|
||||
Direct Play (${data['stream_video_codec'].upper()} ${data['stream_video_full_resolution']})
|
||||
% endif
|
||||
% elif data['media_type'] == 'photo':
|
||||
Direct Play (${data['width']}x${data['height']})
|
||||
|
@@ -355,8 +355,9 @@
|
||||
var session_id = s.session_id;
|
||||
var instance = $('#activity-instance-' + key);
|
||||
|
||||
// Create a new instance if it doesn't exist
|
||||
if (!(instance.length)) {
|
||||
// Create a new instance if it doesn't exist or recreate the entire instance
|
||||
// if the rating key changed (for movies or episodes) with the same session key
|
||||
if (!(instance.length) || (s.media_type !== 'track' && s.rating_key !== instance.data('rating_key').toString())) {
|
||||
create_instances.push(key);
|
||||
getActivityInstance(key);
|
||||
return;
|
||||
@@ -382,7 +383,7 @@
|
||||
// Switching tracks can be under the same session key, so need to update the info.
|
||||
if (s.media_type === 'track') {
|
||||
// Update if artist changed
|
||||
if (s.grandparent_rating_key !== instance.data('grandparent_rating_key')) {
|
||||
if (s.grandparent_rating_key !== instance.data('grandparent_rating_key').toString()) {
|
||||
$('#background-' + key).css('background-image', 'url(pms_image_proxy?img=' + s.art + '&width=500&height=280&opacity=40&background=282828&blur=3&fallback=art&refresh=true)');
|
||||
$('#metadata-grandparent_title-' + key)
|
||||
.attr('href', 'info?rating_key=' + s.grandparent_rating_key)
|
||||
@@ -390,7 +391,7 @@
|
||||
.text(s.original_title || s.grandparent_title);
|
||||
}
|
||||
// Update cover if album changed
|
||||
if (s.parent_rating_key !== instance.data('parent_rating_key')) {
|
||||
if (s.parent_rating_key !== instance.data('parent_rating_key').toString()) {
|
||||
$('#poster-' + key).css('background-image', 'url(pms_image_proxy?img=' + s.parent_thumb + '&width=300&height=300&fallback=poster&refresh=true)');
|
||||
$('#poster-' + key + '-bg').css('background-image', 'url(pms_image_proxy?img=' + s.parent_thumb + '&width=300&height=300&opacity=60&background=282828&blur=3&fallback=poster&refresh=true)');
|
||||
$('#poster-url-' + key)
|
||||
@@ -402,7 +403,7 @@
|
||||
.text(s.parent_title);
|
||||
}
|
||||
// Update cover if track changed
|
||||
if (s.rating_key !== instance.data('rating_key')) {
|
||||
if (s.rating_key !== instance.data('rating_key').toString()) {
|
||||
$('#metadata-grandparent_title-' + key)
|
||||
.attr('href', 'info?rating_key=' + s.grandparent_rating_key)
|
||||
.attr('title', s.original_title || s.grandparent_title)
|
||||
@@ -445,7 +446,7 @@
|
||||
v_res = '4k';
|
||||
break;
|
||||
default:
|
||||
v_res = s.video_resolution + 'p'
|
||||
v_res = s.video_full_resolution;
|
||||
}
|
||||
var sv_res = '';
|
||||
switch (s.stream_video_resolution.toLowerCase()) {
|
||||
@@ -456,7 +457,7 @@
|
||||
sv_res = '4k';
|
||||
break;
|
||||
default:
|
||||
sv_res = s.stream_video_resolution + 'p'
|
||||
sv_res = s.stream_video_full_resolution;
|
||||
}
|
||||
if (s.stream_video_decision === 'transcode') {
|
||||
var hw_d = (s.transcode_hw_decoding === 1) ? ' (HW)' : '';
|
||||
@@ -580,7 +581,14 @@
|
||||
session_key: session_key
|
||||
},
|
||||
complete: function(xhr, status) {
|
||||
$('#currentActivity').append(xhr.responseText);
|
||||
var instance = $('#activity-instance-' + session_key);
|
||||
|
||||
if (instance.length) {
|
||||
instance.replaceWith(xhr.responseText);
|
||||
} else {
|
||||
$('#currentActivity').append(xhr.responseText);
|
||||
}
|
||||
|
||||
$('#activity-instance-' + session_key + ' .dashboard-activity-info-scroller').scrollbar();
|
||||
$('#activity-instance-' + session_key + ' [data-toggle=tooltip]').tooltip({ container: 'body', placement: 'right', delay: 50 });
|
||||
$('#terminate-button-' + session_key).tooltip('destroy').tooltip({ container: 'body', placement: 'left', delay: 50 });
|
||||
|
@@ -50,7 +50,7 @@ media_info_table_options = {
|
||||
expand_details = '<span class="expand-media-info-tooltip" data-toggle="tooltip" title="Show Episodes"><i class="fa fa-plus-circle fa-fw"></i></span>';
|
||||
$(td).html('<div><a href="#"><div style="float: left;">' + expand_details + ' ' + date + '</div></a></div>');
|
||||
} else if (rowData['media_type'] === 'artist') {
|
||||
expand_details = '<span class="expand-media-info-tooltip" data-toggle="tooltip" title="Show Albumns"><i class="fa fa-plus-circle fa-fw"></i></span>';
|
||||
expand_details = '<span class="expand-media-info-tooltip" data-toggle="tooltip" title="Show Albums"><i class="fa fa-plus-circle fa-fw"></i></span>';
|
||||
$(td).html('<div><a href="#"><div style="float: left;">' + expand_details + ' ' + date + '</div></a></div>');
|
||||
} else if (rowData['media_type'] === 'album') {
|
||||
expand_details = '<span class="expand-media-info-tooltip" data-toggle="tooltip" title="Show Tracks"><i class="fa fa-plus-circle fa-fw"></i></span>';
|
||||
|
@@ -96,8 +96,8 @@ DOCUMENTATION :: END
|
||||
% if data['media_type'] != 'track':
|
||||
<tr>
|
||||
<td>Resolution</td>
|
||||
<td>${VIDEO_RESOLUTION_OVERRIDES.get(data['stream_video_resolution'], data['stream_video_resolution'])}</td>
|
||||
<td>${VIDEO_RESOLUTION_OVERRIDES.get(data['video_resolution'], data['video_resolution'])}</td>
|
||||
<td>${data['stream_video_full_resolution']}</td>
|
||||
<td>${data['video_full_resolution']}</td>
|
||||
</tr>
|
||||
% endif
|
||||
<tr>
|
||||
|
@@ -582,12 +582,12 @@ def dbcheck():
|
||||
'view_offset INTEGER DEFAULT 0, duration INTEGER, video_decision TEXT, audio_decision TEXT, '
|
||||
'transcode_decision TEXT, container TEXT, bitrate INTEGER, width INTEGER, height INTEGER, '
|
||||
'video_codec TEXT, video_bitrate INTEGER, video_resolution TEXT, video_width INTEGER, video_height INTEGER, '
|
||||
'video_framerate TEXT, aspect_ratio TEXT, '
|
||||
'video_framerate TEXT, video_scan_type TEXT, video_full_resolution TEXT, aspect_ratio TEXT, '
|
||||
'audio_codec TEXT, audio_bitrate INTEGER, audio_channels INTEGER, subtitle_codec TEXT, '
|
||||
'stream_bitrate INTEGER, stream_video_resolution TEXT, quality_profile TEXT, '
|
||||
'stream_container_decision TEXT, stream_container TEXT, '
|
||||
'stream_video_decision TEXT, stream_video_codec TEXT, stream_video_bitrate INTEGER, stream_video_width INTEGER, '
|
||||
'stream_video_height INTEGER, stream_video_framerate TEXT, '
|
||||
'stream_video_height INTEGER, stream_video_framerate TEXT, stream_video_scan_type TEXT, stream_video_full_resolution TEXT, '
|
||||
'stream_audio_decision TEXT, stream_audio_codec TEXT, stream_audio_bitrate INTEGER, stream_audio_channels INTEGER, '
|
||||
'subtitles INTEGER, stream_subtitle_decision TEXT, stream_subtitle_codec TEXT, '
|
||||
'transcode_protocol TEXT, transcode_container TEXT, '
|
||||
@@ -617,7 +617,7 @@ def dbcheck():
|
||||
'video_decision TEXT, audio_decision TEXT, transcode_decision TEXT, duration INTEGER DEFAULT 0, '
|
||||
'container TEXT, bitrate INTEGER, width INTEGER, height INTEGER, video_bitrate INTEGER, video_bit_depth INTEGER, '
|
||||
'video_codec TEXT, video_codec_level TEXT, video_width INTEGER, video_height INTEGER, video_resolution TEXT, '
|
||||
'video_framerate TEXT, aspect_ratio TEXT, '
|
||||
'video_framerate TEXT, video_scan_type TEXT, video_full_resolution TEXT, aspect_ratio TEXT, '
|
||||
'audio_bitrate INTEGER, audio_codec TEXT, audio_channels INTEGER, transcode_protocol TEXT, '
|
||||
'transcode_container TEXT, transcode_video_codec TEXT, transcode_audio_codec TEXT, '
|
||||
'transcode_audio_channels INTEGER, transcode_width INTEGER, transcode_height INTEGER, '
|
||||
@@ -627,7 +627,7 @@ def dbcheck():
|
||||
'stream_container TEXT, stream_container_decision TEXT, stream_bitrate INTEGER, '
|
||||
'stream_video_decision TEXT, stream_video_bitrate INTEGER, stream_video_codec TEXT, stream_video_codec_level TEXT, '
|
||||
'stream_video_bit_depth INTEGER, stream_video_height INTEGER, stream_video_width INTEGER, stream_video_resolution TEXT, '
|
||||
'stream_video_framerate TEXT, '
|
||||
'stream_video_framerate TEXT, stream_video_scan_type TEXT, stream_video_full_resolution TEXT, '
|
||||
'stream_audio_decision TEXT, stream_audio_codec TEXT, stream_audio_bitrate INTEGER, stream_audio_channels INTEGER, '
|
||||
'stream_subtitle_decision TEXT, stream_subtitle_codec TEXT, stream_subtitle_container TEXT, stream_subtitle_forced INTEGER, '
|
||||
'subtitles INTEGER, subtitle_codec TEXT, synced_version INTEGER, synced_version_profile TEXT, '
|
||||
@@ -1175,6 +1175,24 @@ def dbcheck():
|
||||
'ALTER TABLE sessions ADD COLUMN rating_key_websocket TEXT'
|
||||
)
|
||||
|
||||
# Upgrade sessions table from earlier versions
|
||||
try:
|
||||
c_db.execute('SELECT video_scan_type FROM sessions')
|
||||
except sqlite3.OperationalError:
|
||||
logger.debug(u"Altering database. Updating database table sessions.")
|
||||
c_db.execute(
|
||||
'ALTER TABLE sessions ADD COLUMN video_scan_type TEXT'
|
||||
)
|
||||
c_db.execute(
|
||||
'ALTER TABLE sessions ADD COLUMN video_full_resolution TEXT'
|
||||
)
|
||||
c_db.execute(
|
||||
'ALTER TABLE sessions ADD COLUMN stream_video_scan_type TEXT'
|
||||
)
|
||||
c_db.execute(
|
||||
'ALTER TABLE sessions ADD COLUMN stream_video_full_resolution TEXT'
|
||||
)
|
||||
|
||||
# Upgrade session_history table from earlier versions
|
||||
try:
|
||||
c_db.execute('SELECT reference_id FROM session_history')
|
||||
@@ -1474,6 +1492,45 @@ def dbcheck():
|
||||
except sqlite3.OperationalError:
|
||||
logger.warn(u"Unable to remove NULL values from session_history_media_info table.")
|
||||
|
||||
# Upgrade session_history_media_info table from earlier versions
|
||||
try:
|
||||
c_db.execute('SELECT video_scan_type FROM session_history_media_info')
|
||||
except sqlite3.OperationalError:
|
||||
logger.debug(u"Altering database. Updating database table session_history_media_info.")
|
||||
c_db.execute(
|
||||
'ALTER TABLE session_history_media_info ADD COLUMN video_scan_type TEXT'
|
||||
)
|
||||
c_db.execute(
|
||||
'ALTER TABLE session_history_media_info ADD COLUMN video_full_resolution TEXT'
|
||||
)
|
||||
c_db.execute(
|
||||
'ALTER TABLE session_history_media_info ADD COLUMN stream_video_scan_type TEXT'
|
||||
)
|
||||
c_db.execute(
|
||||
'ALTER TABLE session_history_media_info ADD COLUMN stream_video_full_resolution TEXT'
|
||||
)
|
||||
c_db.execute(
|
||||
'UPDATE session_history_media_info SET video_scan_type = "progressive" '
|
||||
'WHERE video_resolution != ""'
|
||||
)
|
||||
c_db.execute(
|
||||
'UPDATE session_history_media_info SET stream_video_scan_type = "progressive" '
|
||||
'WHERE stream_video_resolution != "" AND stream_video_resolution IS NOT NULL'
|
||||
)
|
||||
c_db.execute(
|
||||
'UPDATE session_history_media_info SET video_full_resolution = (CASE '
|
||||
'WHEN video_resolution = "" OR video_resolution = "SD" OR video_resolution = "4k" THEN video_resolution '
|
||||
'WHEN video_resolution = "sd" THEN "SD" '
|
||||
'ELSE video_resolution || "p" END)'
|
||||
)
|
||||
c_db.execute(
|
||||
'UPDATE session_history_media_info SET stream_video_full_resolution = ( '
|
||||
'CASE WHEN stream_video_resolution = "" OR stream_video_resolution = "SD" OR stream_video_resolution = "4k" '
|
||||
'THEN stream_video_resolution '
|
||||
'WHEN stream_video_resolution = "sd" THEN "SD" '
|
||||
'ELSE stream_video_resolution || "p" END)'
|
||||
)
|
||||
|
||||
# Upgrade users table from earlier versions
|
||||
try:
|
||||
c_db.execute('SELECT do_notify FROM users')
|
||||
|
@@ -17,13 +17,13 @@ import threading
|
||||
import time
|
||||
|
||||
import plexpy
|
||||
import activity_handler
|
||||
import activity_processor
|
||||
import database
|
||||
import helpers
|
||||
import libraries
|
||||
import logger
|
||||
import notification_handler
|
||||
import notifiers
|
||||
import plextv
|
||||
import pmsconnect
|
||||
import web_socket
|
||||
@@ -37,17 +37,23 @@ int_ping_count = 0
|
||||
def check_active_sessions(ws_request=False):
|
||||
|
||||
with monitor_lock:
|
||||
pms_connect = pmsconnect.PmsConnect()
|
||||
session_list = pms_connect.get_current_activity()
|
||||
monitor_db = database.MonitorDatabase()
|
||||
monitor_process = activity_processor.ActivityProcessor()
|
||||
db_streams = monitor_process.get_sessions()
|
||||
|
||||
# Clear the metadata cache
|
||||
for stream in db_streams:
|
||||
activity_handler.delete_metadata_cache(stream['session_key'])
|
||||
|
||||
pms_connect = pmsconnect.PmsConnect()
|
||||
session_list = pms_connect.get_current_activity()
|
||||
|
||||
logger.debug(u"Tautulli Monitor :: Checking for active streams.")
|
||||
|
||||
if session_list:
|
||||
media_container = session_list['sessions']
|
||||
|
||||
# Check our temp table for what we must do with the new streams
|
||||
db_streams = monitor_process.get_sessions()
|
||||
for stream in db_streams:
|
||||
if any(d['session_key'] == str(stream['session_key']) and d['rating_key'] == str(stream['rating_key'])
|
||||
for d in media_container):
|
||||
|
@@ -76,6 +76,8 @@ class ActivityProcessor(object):
|
||||
'video_height': session.get('video_height', ''),
|
||||
'video_resolution': session.get('video_resolution', ''),
|
||||
'video_framerate': session.get('video_framerate', ''),
|
||||
'video_scan_type': session.get('video_scan_type', ''),
|
||||
'video_full_resolution': session.get('video_full_resolution', ''),
|
||||
'aspect_ratio': session.get('aspect_ratio', ''),
|
||||
'audio_codec': session.get('audio_codec', ''),
|
||||
'audio_bitrate': session.get('audio_bitrate', ''),
|
||||
@@ -106,6 +108,8 @@ class ActivityProcessor(object):
|
||||
'stream_video_width': session.get('stream_video_width', ''),
|
||||
'stream_video_height': session.get('stream_video_height', ''),
|
||||
'stream_video_framerate': session.get('stream_video_framerate', ''),
|
||||
'stream_video_scan_type': session.get('stream_video_scan_type', ''),
|
||||
'stream_video_full_resolution': session.get('stream_video_full_resolution', ''),
|
||||
'stream_audio_decision': session.get('stream_audio_decision', ''),
|
||||
'stream_audio_codec': session.get('stream_audio_codec', ''),
|
||||
'stream_audio_bitrate': session.get('stream_audio_bitrate', ''),
|
||||
@@ -347,6 +351,8 @@ class ActivityProcessor(object):
|
||||
'video_height': session['video_height'],
|
||||
'video_resolution': session['video_resolution'],
|
||||
'video_framerate': session['video_framerate'],
|
||||
'video_scan_type': session['video_scan_type'],
|
||||
'video_full_resolution': session['video_full_resolution'],
|
||||
'aspect_ratio': session['aspect_ratio'],
|
||||
'audio_codec': session['audio_codec'],
|
||||
'audio_bitrate': session['audio_bitrate'],
|
||||
@@ -379,6 +385,8 @@ class ActivityProcessor(object):
|
||||
'stream_video_width': session['stream_video_width'],
|
||||
'stream_video_resolution': session['stream_video_resolution'],
|
||||
'stream_video_framerate': session['stream_video_framerate'],
|
||||
'stream_video_scan_type': session['stream_video_scan_type'],
|
||||
'stream_video_full_resolution': session['stream_video_full_resolution'],
|
||||
'stream_audio_decision': session['stream_audio_decision'],
|
||||
'stream_audio_codec': session['stream_audio_codec'],
|
||||
'stream_audio_bitrate': session['stream_audio_bitrate'],
|
||||
|
@@ -119,11 +119,6 @@ AUDIO_CODEC_OVERRIDES = {
|
||||
|
||||
VIDEO_RESOLUTION_OVERRIDES = {
|
||||
'sd': 'SD',
|
||||
'480': '480p',
|
||||
'540': '540p',
|
||||
'576': '576p',
|
||||
'720': '720p',
|
||||
'1080': '1080p',
|
||||
'4k': '4k'
|
||||
}
|
||||
|
||||
@@ -168,11 +163,11 @@ HW_DECODERS = [
|
||||
'dxva2',
|
||||
'videotoolbox',
|
||||
'mediacodecndk',
|
||||
'vaapi'
|
||||
'vaapi',
|
||||
'nvdec'
|
||||
]
|
||||
HW_ENCODERS = [
|
||||
'qsv',
|
||||
'nvenc',
|
||||
'mf',
|
||||
'videotoolbox',
|
||||
'mediacodecndk',
|
||||
@@ -366,8 +361,10 @@ NOTIFICATION_PARAMETERS = [
|
||||
{'name': 'Stream Video Bitrate', 'type': 'int', 'value': 'stream_video_bitrate', 'description': 'The video bitrate (in kbps) of the stream.'},
|
||||
{'name': 'Stream Video Bit Depth', 'type': 'int', 'value': 'stream_video_bit_depth', 'description': 'The video bit depth of the stream.'},
|
||||
{'name': 'Stream Video Framerate', 'type': 'str', 'value': 'stream_video_framerate', 'description': 'The video framerate of the stream.'},
|
||||
{'name': 'Stream Video Full Resolution', 'type': 'str', 'value': 'stream_video_full_resolution', 'description': 'The video resolution of the stream with scan type.'},
|
||||
{'name': 'Stream Video Ref Frames', 'type': 'int', 'value': 'stream_video_ref_frames', 'description': 'The video reference frames of the stream.'},
|
||||
{'name': 'Stream Video Resolution', 'type': 'str', 'value': 'stream_video_resolution', 'description': 'The video resolution of the stream.'},
|
||||
{'name': 'Stream Video Scan Type', 'type': 'str', 'value': 'stream_video_scan_type', 'description': 'The video scan type of the stream.'},
|
||||
{'name': 'Stream Video Height', 'type': 'int', 'value': 'stream_video_height', 'description': 'The video height of the stream.'},
|
||||
{'name': 'Stream Video Width', 'type': 'int', 'value': 'stream_video_width', 'description': 'The video width of the stream.'},
|
||||
{'name': 'Stream Video Language', 'type': 'str', 'value': 'stream_video_language', 'description': 'The video language of the stream.'},
|
||||
@@ -430,7 +427,7 @@ NOTIFICATION_PARAMETERS = [
|
||||
{'name': 'Album Count', 'type': 'int', 'value': 'album_count', 'description': 'The number of albums.'},
|
||||
{'name': 'Track Count', 'type': 'int', 'value': 'track_count', 'description': 'The number of tracks.'},
|
||||
{'name': 'Year', 'type': 'int', 'value': 'year', 'description': 'The release year for the item.'},
|
||||
{'name': 'Release Date', 'type': 'int', 'value': 'release_date', 'description': 'The release date (in date format) for the item.'},
|
||||
{'name': 'Release Date', 'type': 'str', 'value': 'release_date', 'description': 'The release date (in date format) for the item.'},
|
||||
{'name': 'Air Date', 'type': 'str', 'value': 'air_date', 'description': 'The air date (in date format) for the item.'},
|
||||
{'name': 'Added Date', 'type': 'str', 'value': 'added_date', 'description': 'The date (in date format) the item was added to Plex.'},
|
||||
{'name': 'Updated Date', 'type': 'str', 'value': 'updated_date', 'description': 'The date (in date format) the item was updated on Plex.'},
|
||||
@@ -469,8 +466,10 @@ NOTIFICATION_PARAMETERS = [
|
||||
{'name': 'Video Bitrate', 'type': 'int', 'value': 'video_bitrate', 'description': 'The video bitrate of the original media.'},
|
||||
{'name': 'Video Bit Depth', 'type': 'int', 'value': 'video_bit_depth', 'description': 'The video bit depth of the original media.'},
|
||||
{'name': 'Video Framerate', 'type': 'str', 'value': 'video_framerate', 'description': 'The video framerate of the original media.'},
|
||||
{'name': 'Video Full Resolution', 'type': 'str', 'value': 'video_full_resolution', 'description': 'The video resolution of the original media with scan type.'},
|
||||
{'name': 'Video Ref Frames', 'type': 'int', 'value': 'video_ref_frames', 'description': 'The video reference frames of the original media.'},
|
||||
{'name': 'Video Resolution', 'type': 'str', 'value': 'video_resolution', 'description': 'The video resolution of the original media.'},
|
||||
{'name': 'Video Scan Tpye', 'type': 'str', 'value': 'video_scan_type', 'description': 'The video scan type of the original media.'},
|
||||
{'name': 'Video Height', 'type': 'int', 'value': 'video_height', 'description': 'The video height of the original media.'},
|
||||
{'name': 'Video Width', 'type': 'int', 'value': 'video_width', 'description': 'The video width of the original media.'},
|
||||
{'name': 'Video Language', 'type': 'str', 'value': 'video_language', 'description': 'The video language of the original media.'},
|
||||
|
@@ -297,7 +297,7 @@ class DataFactory(object):
|
||||
' >= datetime("now", "-%s days", "localtime") ' \
|
||||
' AND session_history.media_type = "movie" ' \
|
||||
' GROUP BY %s) AS t ' \
|
||||
'GROUP BY t.full_title ' \
|
||||
'GROUP BY t.full_title, t.year ' \
|
||||
'ORDER BY %s DESC, started DESC ' \
|
||||
'LIMIT %s ' % (time_range, group_by, sort_type, stats_count)
|
||||
result = monitor_db.select(query)
|
||||
@@ -348,7 +348,7 @@ class DataFactory(object):
|
||||
' >= datetime("now", "-%s days", "localtime") ' \
|
||||
' AND session_history.media_type = "movie" ' \
|
||||
' GROUP BY %s) AS t ' \
|
||||
'GROUP BY t.full_title ' \
|
||||
'GROUP BY t.full_title, t.year ' \
|
||||
'ORDER BY users_watched DESC, %s DESC, started DESC ' \
|
||||
'LIMIT %s ' % (time_range, group_by, sort_type, stats_count)
|
||||
result = monitor_db.select(query)
|
||||
@@ -875,12 +875,12 @@ class DataFactory(object):
|
||||
user_cond = 'AND %s.user_id = %s ' % (table, session.get_session_user_id())
|
||||
|
||||
if row_id:
|
||||
query = 'SELECT bitrate, video_resolution, ' \
|
||||
query = 'SELECT bitrate, video_full_resolution, ' \
|
||||
'optimized_version, optimized_version_profile, optimized_version_title, ' \
|
||||
'synced_version, synced_version_profile, ' \
|
||||
'container, video_codec, video_bitrate, video_width, video_height, video_framerate, aspect_ratio, ' \
|
||||
'audio_codec, audio_bitrate, audio_channels, subtitle_codec, ' \
|
||||
'stream_bitrate, stream_video_resolution, quality_profile, stream_container_decision, stream_container, ' \
|
||||
'stream_bitrate, stream_video_full_resolution, quality_profile, stream_container_decision, stream_container, ' \
|
||||
'stream_video_decision, stream_video_codec, stream_video_bitrate, stream_video_width, stream_video_height, ' \
|
||||
'stream_video_framerate, ' \
|
||||
'stream_audio_decision, stream_audio_codec, stream_audio_bitrate, stream_audio_channels, ' \
|
||||
@@ -896,12 +896,12 @@ class DataFactory(object):
|
||||
'WHERE session_history_media_info.id = ? %s' % user_cond
|
||||
result = monitor_db.select(query, args=[row_id])
|
||||
elif session_key:
|
||||
query = 'SELECT bitrate, video_resolution, ' \
|
||||
query = 'SELECT bitrate, video_full_resolution, ' \
|
||||
'optimized_version, optimized_version_profile, optimized_version_title, ' \
|
||||
'synced_version, synced_version_profile, ' \
|
||||
'container, video_codec, video_bitrate, video_width, video_height, video_framerate, aspect_ratio, ' \
|
||||
'audio_codec, audio_bitrate, audio_channels, subtitle_codec, ' \
|
||||
'stream_bitrate, stream_video_resolution, quality_profile, stream_container_decision, stream_container, ' \
|
||||
'stream_bitrate, stream_video_full_resolution, quality_profile, stream_container_decision, stream_container, ' \
|
||||
'stream_video_decision, stream_video_codec, stream_video_bitrate, stream_video_width, stream_video_height, ' \
|
||||
'stream_video_framerate, ' \
|
||||
'stream_audio_decision, stream_audio_codec, stream_audio_bitrate, stream_audio_channels, ' \
|
||||
@@ -924,7 +924,7 @@ class DataFactory(object):
|
||||
|
||||
# For backwards compatibility. Pick one new Tautulli key to check and override with old values.
|
||||
if not item['stream_container']:
|
||||
item['stream_video_resolution'] = item['video_resolution']
|
||||
item['stream_video_full_resolution'] = item['video_full_resolution']
|
||||
item['stream_container'] = item['transcode_container'] or item['container']
|
||||
item['stream_video_decision'] = item['video_decision']
|
||||
item['stream_video_codec'] = item['transcode_video_codec'] or item['video_codec']
|
||||
@@ -938,7 +938,7 @@ class DataFactory(object):
|
||||
pre_tautulli = 1
|
||||
|
||||
stream_output = {'bitrate': item['bitrate'],
|
||||
'video_resolution': item['video_resolution'],
|
||||
'video_full_resolution': item['video_full_resolution'],
|
||||
'optimized_version': item['optimized_version'],
|
||||
'optimized_version_profile': item['optimized_version_profile'],
|
||||
'optimized_version_title': item['optimized_version_title'],
|
||||
@@ -956,7 +956,7 @@ class DataFactory(object):
|
||||
'audio_channels': item['audio_channels'],
|
||||
'subtitle_codec': item['subtitle_codec'],
|
||||
'stream_bitrate': item['stream_bitrate'],
|
||||
'stream_video_resolution': item['stream_video_resolution'],
|
||||
'stream_video_full_resolution': item['stream_video_full_resolution'],
|
||||
'quality_profile': item['quality_profile'],
|
||||
'stream_container_decision': item['stream_container_decision'],
|
||||
'stream_container': item['stream_container'],
|
||||
|
@@ -698,7 +698,7 @@ class Graphs(object):
|
||||
|
||||
try:
|
||||
if y_axis == 'plays':
|
||||
query = 'SELECT UPPER(session_history_media_info.video_resolution) AS resolution, ' \
|
||||
query = 'SELECT session_history_media_info.video_full_resolution AS resolution, ' \
|
||||
'SUM(CASE WHEN session_history_media_info.transcode_decision = "direct play" ' \
|
||||
'THEN 1 ELSE 0 END) AS dp_count, ' \
|
||||
'SUM(CASE WHEN session_history_media_info.transcode_decision = "copy" ' \
|
||||
@@ -717,7 +717,7 @@ class Graphs(object):
|
||||
|
||||
result = monitor_db.select(query)
|
||||
else:
|
||||
query = 'SELECT UPPER(session_history_media_info.video_resolution) AS resolution,' \
|
||||
query = 'SELECT session_history_media_info.video_full_resolution AS resolution,' \
|
||||
'SUM(CASE WHEN session_history_media_info.transcode_decision = "direct play" ' \
|
||||
'AND session_history.stopped > 0 THEN (session_history.stopped - session_history.started) ' \
|
||||
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS dp_count, ' \
|
||||
@@ -749,10 +749,6 @@ class Graphs(object):
|
||||
series_3 = []
|
||||
|
||||
for item in result:
|
||||
if item['resolution'] not in ('4k', 'unknown'):
|
||||
item['resolution'] = item['resolution'].upper()
|
||||
if item['resolution'].isdigit():
|
||||
item['resolution'] += 'p'
|
||||
categories.append(item['resolution'])
|
||||
series_1.append(item['dp_count'])
|
||||
series_2.append(item['ds_count'])
|
||||
@@ -789,7 +785,7 @@ class Graphs(object):
|
||||
try:
|
||||
if y_axis == 'plays':
|
||||
query = 'SELECT ' \
|
||||
'(CASE WHEN session_history_media_info.stream_video_resolution IS NULL THEN ' \
|
||||
'(CASE WHEN session_history_media_info.stream_video_full_resolution IS NULL THEN ' \
|
||||
'(CASE WHEN session_history_media_info.video_decision = "transcode" THEN ' \
|
||||
'(CASE ' \
|
||||
'WHEN session_history_media_info.transcode_height <= 360 THEN "SD" ' \
|
||||
@@ -799,8 +795,8 @@ class Graphs(object):
|
||||
'WHEN session_history_media_info.transcode_height <= 1080 THEN "1080" ' \
|
||||
'WHEN session_history_media_info.transcode_height <= 1440 THEN "QHD" ' \
|
||||
'WHEN session_history_media_info.transcode_height <= 2160 THEN "4k" ' \
|
||||
'ELSE "unknown" END) ELSE UPPER(session_history_media_info.video_resolution) END) ' \
|
||||
'ELSE UPPER(session_history_media_info.stream_video_resolution) END) AS resolution, ' \
|
||||
'ELSE "unknown" END) ELSE session_history_media_info.video_full_resolution END) ' \
|
||||
'ELSE session_history_media_info.stream_video_full_resolution END) AS resolution, ' \
|
||||
'SUM(CASE WHEN session_history_media_info.transcode_decision = "direct play" ' \
|
||||
'THEN 1 ELSE 0 END) AS dp_count, ' \
|
||||
'SUM(CASE WHEN session_history_media_info.transcode_decision = "copy" ' \
|
||||
@@ -820,7 +816,7 @@ class Graphs(object):
|
||||
result = monitor_db.select(query)
|
||||
else:
|
||||
query = 'SELECT ' \
|
||||
'(CASE WHEN session_history_media_info.stream_video_resolution IS NULL THEN ' \
|
||||
'(CASE WHEN session_history_media_info.stream_video_full_resolution IS NULL THEN ' \
|
||||
'(CASE WHEN session_history_media_info.video_decision = "transcode" THEN ' \
|
||||
'(CASE ' \
|
||||
'WHEN session_history_media_info.transcode_height <= 360 THEN "SD" ' \
|
||||
@@ -830,8 +826,8 @@ class Graphs(object):
|
||||
'WHEN session_history_media_info.transcode_height <= 1080 THEN "1080" ' \
|
||||
'WHEN session_history_media_info.transcode_height <= 1440 THEN "QHD" ' \
|
||||
'WHEN session_history_media_info.transcode_height <= 2160 THEN "4k" ' \
|
||||
'ELSE "unknown" END) ELSE UPPER(session_history_media_info.video_resolution) END) ' \
|
||||
'ELSE UPPER(session_history_media_info.stream_video_resolution) END) AS resolution, ' \
|
||||
'ELSE "unknown" END) ELSE session_history_media_info.video_full_resolution END) ' \
|
||||
'ELSE session_history_media_info.stream_video_full_resolution END) AS resolution, ' \
|
||||
'SUM(CASE WHEN session_history_media_info.transcode_decision = "direct play" ' \
|
||||
'AND session_history.stopped > 0 THEN (session_history.stopped - session_history.started) ' \
|
||||
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS dp_count, ' \
|
||||
@@ -863,10 +859,6 @@ class Graphs(object):
|
||||
series_3 = []
|
||||
|
||||
for item in result:
|
||||
if item['resolution'] not in ('4k', 'unknown'):
|
||||
item['resolution'] = item['resolution'].upper()
|
||||
if item['resolution'].isdigit():
|
||||
item['resolution'] += 'p'
|
||||
categories.append(item['resolution'])
|
||||
series_1.append(item['dp_count'])
|
||||
series_2.append(item['ds_count'])
|
||||
|
@@ -784,8 +784,10 @@ def build_media_notify_params(notify_action=None, session=None, timeline=None, m
|
||||
'stream_video_bitrate': notify_params['stream_video_bitrate'],
|
||||
'stream_video_bit_depth': notify_params['stream_video_bit_depth'],
|
||||
'stream_video_framerate': notify_params['stream_video_framerate'],
|
||||
'stream_video_full_resolution': notify_params['stream_video_full_resolution'],
|
||||
'stream_video_ref_frames': notify_params['stream_video_ref_frames'],
|
||||
'stream_video_resolution': notify_params['stream_video_resolution'],
|
||||
'stream_video_scan_type': notify_params['stream_video_scan_type'],
|
||||
'stream_video_height': notify_params['stream_video_height'],
|
||||
'stream_video_width': notify_params['stream_video_width'],
|
||||
'stream_video_language': notify_params['stream_video_language'],
|
||||
@@ -890,8 +892,10 @@ def build_media_notify_params(notify_action=None, session=None, timeline=None, m
|
||||
'video_bitrate': notify_params['video_bitrate'],
|
||||
'video_bit_depth': notify_params['video_bit_depth'],
|
||||
'video_framerate': notify_params['video_framerate'],
|
||||
'video_full_resolution': notify_params['video_full_resolution'],
|
||||
'video_ref_frames': notify_params['video_ref_frames'],
|
||||
'video_resolution': notify_params['video_resolution'],
|
||||
'video_scan_type': notify_params['video_scan_type'],
|
||||
'video_height': notify_params['height'],
|
||||
'video_width': notify_params['width'],
|
||||
'video_language': notify_params['video_language'],
|
||||
@@ -1101,6 +1105,8 @@ def build_notify_text(subject='', body='', notify_action=None, parameters=None,
|
||||
|
||||
|
||||
def strip_tag(data, agent_id=None):
|
||||
# Substitute temporary tokens for < and > in parameter prefix and suffix
|
||||
data = re.sub(r'{.+?}', lambda m: m.group().replace('<', '%temp_lt_token%').replace('>', '%temp_gt_token%'), data)
|
||||
|
||||
if agent_id == 7:
|
||||
# Allow tags b, i, u, a[href], font[color] for Pushover
|
||||
@@ -1109,11 +1115,11 @@ def strip_tag(data, agent_id=None):
|
||||
'u': [],
|
||||
'a': ['href'],
|
||||
'font': ['color']}
|
||||
return bleach.clean(data, tags=whitelist.keys(), attributes=whitelist, strip=True)
|
||||
data = bleach.clean(data, tags=whitelist.keys(), attributes=whitelist, strip=True)
|
||||
|
||||
elif agent_id in (10, 14, 20):
|
||||
# Don't remove tags for Email, Slack, and Discord
|
||||
return data
|
||||
pass
|
||||
|
||||
elif agent_id == 13:
|
||||
# Allow tags b, i, code, pre, a[href] for Telegram
|
||||
@@ -1122,11 +1128,14 @@ def strip_tag(data, agent_id=None):
|
||||
'code': [],
|
||||
'pre': [],
|
||||
'a': ['href']}
|
||||
return bleach.clean(data, tags=whitelist.keys(), attributes=whitelist, strip=True)
|
||||
data = bleach.clean(data, tags=whitelist.keys(), attributes=whitelist, strip=True)
|
||||
|
||||
else:
|
||||
whitelist = {}
|
||||
return bleach.clean(data, tags=whitelist.keys(), attributes=whitelist, strip=True)
|
||||
data = bleach.clean(data, tags=whitelist.keys(), attributes=whitelist, strip=True)
|
||||
|
||||
# Resubstitute temporary tokens for < and > in parameter prefix and suffix
|
||||
return data.replace('%temp_lt_token%', '<').replace('%temp_gt_token%', '>')
|
||||
|
||||
|
||||
def format_group_index(group_keys):
|
||||
|
@@ -710,6 +710,8 @@ class PmsConnect(object):
|
||||
'updated_at': helpers.get_xml_attr(metadata_main, 'updatedAt'),
|
||||
'last_viewed_at': helpers.get_xml_attr(metadata_main, 'lastViewedAt'),
|
||||
'guid': helpers.get_xml_attr(metadata_main, 'guid'),
|
||||
'parent_guid': helpers.get_xml_attr(metadata_main, 'parentGuid'),
|
||||
'grandparent_guid': helpers.get_xml_attr(metadata_main, 'grandparentGuid'),
|
||||
'directors': directors,
|
||||
'writers': writers,
|
||||
'actors': actors,
|
||||
@@ -760,6 +762,8 @@ class PmsConnect(object):
|
||||
'updated_at': helpers.get_xml_attr(metadata_main, 'updatedAt'),
|
||||
'last_viewed_at': helpers.get_xml_attr(metadata_main, 'lastViewedAt'),
|
||||
'guid': helpers.get_xml_attr(metadata_main, 'guid'),
|
||||
'parent_guid': helpers.get_xml_attr(metadata_main, 'parentGuid'),
|
||||
'grandparent_guid': helpers.get_xml_attr(metadata_main, 'grandparentGuid'),
|
||||
'directors': directors,
|
||||
'writers': writers,
|
||||
'actors': actors,
|
||||
@@ -807,6 +811,8 @@ class PmsConnect(object):
|
||||
'updated_at': helpers.get_xml_attr(metadata_main, 'updatedAt'),
|
||||
'last_viewed_at': helpers.get_xml_attr(metadata_main, 'lastViewedAt'),
|
||||
'guid': helpers.get_xml_attr(metadata_main, 'guid'),
|
||||
'parent_guid': helpers.get_xml_attr(metadata_main, 'parentGuid'),
|
||||
'grandparent_guid': helpers.get_xml_attr(metadata_main, 'grandparentGuid'),
|
||||
'directors': show_details['directors'],
|
||||
'writers': show_details['writers'],
|
||||
'actors': show_details['actors'],
|
||||
@@ -871,6 +877,8 @@ class PmsConnect(object):
|
||||
'updated_at': helpers.get_xml_attr(metadata_main, 'updatedAt'),
|
||||
'last_viewed_at': helpers.get_xml_attr(metadata_main, 'lastViewedAt'),
|
||||
'guid': helpers.get_xml_attr(metadata_main, 'guid'),
|
||||
'parent_guid': helpers.get_xml_attr(metadata_main, 'parentGuid'),
|
||||
'grandparent_guid': helpers.get_xml_attr(metadata_main, 'grandparentGuid'),
|
||||
'directors': directors,
|
||||
'writers': writers,
|
||||
'actors': show_details['actors'],
|
||||
@@ -917,6 +925,8 @@ class PmsConnect(object):
|
||||
'updated_at': helpers.get_xml_attr(metadata_main, 'updatedAt'),
|
||||
'last_viewed_at': helpers.get_xml_attr(metadata_main, 'lastViewedAt'),
|
||||
'guid': helpers.get_xml_attr(metadata_main, 'guid'),
|
||||
'parent_guid': helpers.get_xml_attr(metadata_main, 'parentGuid'),
|
||||
'grandparent_guid': helpers.get_xml_attr(metadata_main, 'grandparentGuid'),
|
||||
'directors': directors,
|
||||
'writers': writers,
|
||||
'actors': actors,
|
||||
@@ -964,6 +974,8 @@ class PmsConnect(object):
|
||||
'updated_at': helpers.get_xml_attr(metadata_main, 'updatedAt'),
|
||||
'last_viewed_at': helpers.get_xml_attr(metadata_main, 'lastViewedAt'),
|
||||
'guid': helpers.get_xml_attr(metadata_main, 'guid'),
|
||||
'parent_guid': helpers.get_xml_attr(metadata_main, 'parentGuid'),
|
||||
'grandparent_guid': helpers.get_xml_attr(metadata_main, 'grandparentGuid'),
|
||||
'directors': directors,
|
||||
'writers': writers,
|
||||
'actors': actors,
|
||||
@@ -1014,6 +1026,8 @@ class PmsConnect(object):
|
||||
'updated_at': helpers.get_xml_attr(metadata_main, 'updatedAt'),
|
||||
'last_viewed_at': helpers.get_xml_attr(metadata_main, 'lastViewedAt'),
|
||||
'guid': helpers.get_xml_attr(metadata_main, 'guid'),
|
||||
'parent_guid': helpers.get_xml_attr(metadata_main, 'parentGuid'),
|
||||
'grandparent_guid': helpers.get_xml_attr(metadata_main, 'grandparentGuid'),
|
||||
'directors': directors,
|
||||
'writers': writers,
|
||||
'actors': actors,
|
||||
@@ -1060,6 +1074,8 @@ class PmsConnect(object):
|
||||
'updated_at': helpers.get_xml_attr(metadata_main, 'updatedAt'),
|
||||
'last_viewed_at': helpers.get_xml_attr(metadata_main, 'lastViewedAt'),
|
||||
'guid': helpers.get_xml_attr(metadata_main, 'guid'),
|
||||
'parent_guid': helpers.get_xml_attr(metadata_main, 'parentGuid'),
|
||||
'grandparent_guid': helpers.get_xml_attr(metadata_main, 'grandparentGuid'),
|
||||
'directors': directors,
|
||||
'writers': writers,
|
||||
'actors': actors,
|
||||
@@ -1107,6 +1123,8 @@ class PmsConnect(object):
|
||||
'updated_at': helpers.get_xml_attr(metadata_main, 'updatedAt'),
|
||||
'last_viewed_at': helpers.get_xml_attr(metadata_main, 'lastViewedAt'),
|
||||
'guid': helpers.get_xml_attr(metadata_main, 'guid'),
|
||||
'parent_guid': helpers.get_xml_attr(metadata_main, 'parentGuid'),
|
||||
'grandparent_guid': helpers.get_xml_attr(metadata_main, 'grandparentGuid'),
|
||||
'directors': directors,
|
||||
'writers': writers,
|
||||
'actors': actors,
|
||||
@@ -1156,6 +1174,8 @@ class PmsConnect(object):
|
||||
'updated_at': helpers.get_xml_attr(metadata_main, 'updatedAt'),
|
||||
'last_viewed_at': helpers.get_xml_attr(metadata_main, 'lastViewedAt'),
|
||||
'guid': helpers.get_xml_attr(metadata_main, 'guid'),
|
||||
'parent_guid': helpers.get_xml_attr(metadata_main, 'parentGuid'),
|
||||
'grandparent_guid': helpers.get_xml_attr(metadata_main, 'grandparentGuid'),
|
||||
'child_count': helpers.get_xml_attr(metadata_main, 'childCount'),
|
||||
'directors': directors,
|
||||
'writers': writers,
|
||||
@@ -1202,6 +1222,8 @@ class PmsConnect(object):
|
||||
'updated_at': helpers.get_xml_attr(metadata_main, 'updatedAt'),
|
||||
'last_viewed_at': helpers.get_xml_attr(metadata_main, 'lastViewedAt'),
|
||||
'guid': helpers.get_xml_attr(metadata_main, 'guid'),
|
||||
'parent_guid': helpers.get_xml_attr(metadata_main, 'parentGuid'),
|
||||
'grandparent_guid': helpers.get_xml_attr(metadata_main, 'grandparentGuid'),
|
||||
'directors': directors,
|
||||
'writers': writers,
|
||||
'actors': actors,
|
||||
@@ -1220,6 +1242,7 @@ class PmsConnect(object):
|
||||
medias = []
|
||||
media_items = metadata_main.getElementsByTagName('Media')
|
||||
for media in media_items:
|
||||
video_full_resolution_scan_type = None
|
||||
|
||||
parts = []
|
||||
part_items = media.getElementsByTagName('Part')
|
||||
@@ -1229,6 +1252,10 @@ class PmsConnect(object):
|
||||
stream_items = part.getElementsByTagName('Stream')
|
||||
for stream in stream_items:
|
||||
if helpers.get_xml_attr(stream, 'streamType') == '1':
|
||||
video_scan_type = helpers.get_xml_attr(stream, 'scanType')
|
||||
if video_full_resolution_scan_type is None:
|
||||
video_full_resolution_scan_type = video_scan_type
|
||||
|
||||
streams.append({'id': helpers.get_xml_attr(stream, 'id'),
|
||||
'type': helpers.get_xml_attr(stream, 'streamType'),
|
||||
'video_codec': helpers.get_xml_attr(stream, 'codec'),
|
||||
@@ -1242,6 +1269,7 @@ class PmsConnect(object):
|
||||
'video_language': helpers.get_xml_attr(stream, 'language'),
|
||||
'video_language_code': helpers.get_xml_attr(stream, 'languageCode'),
|
||||
'video_profile': helpers.get_xml_attr(stream, 'profile'),
|
||||
'video_scan_type': helpers.get_xml_attr(stream, 'scanType'),
|
||||
'selected': int(helpers.get_xml_attr(stream, 'selected') == '1')
|
||||
})
|
||||
|
||||
@@ -1281,6 +1309,13 @@ class PmsConnect(object):
|
||||
'selected': int(helpers.get_xml_attr(part, 'selected') == '1')
|
||||
})
|
||||
|
||||
video_resolution = helpers.get_xml_attr(media, 'videoResolution').lower()
|
||||
video_full_resolution = ''
|
||||
if video_full_resolution_scan_type is not None:
|
||||
video_full_resolution = common.VIDEO_RESOLUTION_OVERRIDES.get(
|
||||
video_resolution, video_resolution + (video_full_resolution_scan_type[:1] or 'p')
|
||||
)
|
||||
|
||||
audio_channels = helpers.get_xml_attr(media, 'audioChannels')
|
||||
|
||||
medias.append({'id': helpers.get_xml_attr(media, 'id'),
|
||||
@@ -1290,7 +1325,8 @@ class PmsConnect(object):
|
||||
'width': helpers.get_xml_attr(media, 'width'),
|
||||
'aspect_ratio': helpers.get_xml_attr(media, 'aspectRatio'),
|
||||
'video_codec': helpers.get_xml_attr(media, 'videoCodec'),
|
||||
'video_resolution': helpers.get_xml_attr(media, 'videoResolution'),
|
||||
'video_resolution': video_resolution,
|
||||
'video_full_resolution': video_full_resolution,
|
||||
'video_framerate': helpers.get_xml_attr(media, 'videoFrameRate'),
|
||||
'video_profile': helpers.get_xml_attr(media, 'videoProfile'),
|
||||
'audio_codec': helpers.get_xml_attr(media, 'audioCodec'),
|
||||
@@ -1300,7 +1336,9 @@ class PmsConnect(object):
|
||||
'optimized_version': int(helpers.get_xml_attr(media, 'proxyType') == '42'),
|
||||
'parts': parts
|
||||
})
|
||||
|
||||
|
||||
video_full_resolution = helpers.get_xml_attr(media, 'videoResolution').lower()
|
||||
|
||||
metadata['media_info'] = medias
|
||||
|
||||
if metadata:
|
||||
@@ -1644,13 +1682,16 @@ class PmsConnect(object):
|
||||
video_stream_info = audio_stream_info = subtitle_stream_info = None
|
||||
for stream in stream_media_parts_info.getElementsByTagName('Stream'):
|
||||
if helpers.get_xml_attr(stream, 'streamType') == '1':
|
||||
video_stream_info = stream
|
||||
if video_stream_info is None or helpers.get_xml_attr(stream, 'selected') == '1':
|
||||
video_stream_info = stream
|
||||
|
||||
elif helpers.get_xml_attr(stream, 'streamType') == '2' and helpers.get_xml_attr(stream, 'selected') == '1':
|
||||
audio_stream_info = stream
|
||||
elif helpers.get_xml_attr(stream, 'streamType') == '2':
|
||||
if audio_stream_info is None or helpers.get_xml_attr(stream, 'selected') == '1':
|
||||
audio_stream_info = stream
|
||||
|
||||
elif helpers.get_xml_attr(stream, 'streamType') == '3' and helpers.get_xml_attr(stream, 'selected') == '1':
|
||||
subtitle_stream_info = stream
|
||||
elif helpers.get_xml_attr(stream, 'streamType') == '3':
|
||||
if subtitle_stream_info is None or helpers.get_xml_attr(stream, 'selected') == '1':
|
||||
subtitle_stream_info = stream
|
||||
|
||||
video_id = audio_id = subtitle_id = None
|
||||
if video_stream_info:
|
||||
@@ -1661,6 +1702,7 @@ class PmsConnect(object):
|
||||
'stream_video_ref_frames': helpers.get_xml_attr(video_stream_info, 'refFrames'),
|
||||
'stream_video_language': helpers.get_xml_attr(video_stream_info, 'language'),
|
||||
'stream_video_language_code': helpers.get_xml_attr(video_stream_info, 'languageCode'),
|
||||
'stream_video_scan_type': helpers.get_xml_attr(video_stream_info, 'scanType'),
|
||||
'stream_video_decision': helpers.get_xml_attr(video_stream_info, 'decision') or 'direct play'
|
||||
}
|
||||
else:
|
||||
@@ -1670,6 +1712,7 @@ class PmsConnect(object):
|
||||
'stream_video_ref_frames': '',
|
||||
'stream_video_language': '',
|
||||
'stream_video_language_code': '',
|
||||
'stream_video_scan_type': '',
|
||||
'stream_video_decision': ''
|
||||
}
|
||||
|
||||
@@ -1730,7 +1773,7 @@ class PmsConnect(object):
|
||||
if helpers.cast_to_int(stream_video_width) >= 3840:
|
||||
stream_video_resolution = '4k'
|
||||
else:
|
||||
stream_video_resolution = helpers.get_xml_attr(stream_media_info, 'videoResolution').rstrip('p')
|
||||
stream_video_resolution = helpers.get_xml_attr(stream_media_info, 'videoResolution').rstrip('p').lower()
|
||||
|
||||
stream_audio_channels = helpers.get_xml_attr(stream_media_info, 'audioChannels')
|
||||
|
||||
@@ -1810,7 +1853,7 @@ class PmsConnect(object):
|
||||
'height': helpers.get_xml_attr(stream_media_info, 'height'),
|
||||
'width': helpers.get_xml_attr(stream_media_info, 'width'),
|
||||
'video_codec': helpers.get_xml_attr(stream_media_info, 'videoCodec'),
|
||||
'video_resolution': helpers.get_xml_attr(stream_media_info, 'videoResolution'),
|
||||
'video_resolution': helpers.get_xml_attr(stream_media_info, 'videoResolution').lower(),
|
||||
'audio_codec': helpers.get_xml_attr(stream_media_info, 'audioCodec'),
|
||||
'audio_channels': audio_channels,
|
||||
'audio_channel_layout': common.AUDIO_CHANNELS.get(audio_channels, audio_channels),
|
||||
@@ -1849,6 +1892,7 @@ class PmsConnect(object):
|
||||
'video_width': '',
|
||||
'video_language': '',
|
||||
'video_language_code': '',
|
||||
'video_scan_type': '',
|
||||
'video_profile': ''
|
||||
}
|
||||
source_audio_details = {'id': '',
|
||||
@@ -1919,6 +1963,12 @@ class PmsConnect(object):
|
||||
if transcode_details['transcode_video_codec'] == '*':
|
||||
transcode_details['transcode_video_codec'] = source_video_details['video_codec']
|
||||
|
||||
if media_type in ('movie', 'episode', 'clip'):
|
||||
# Set the full resolution by combining stream_video_resolution and stream_video_scan_type
|
||||
stream_details['stream_video_full_resolution'] = common.VIDEO_RESOLUTION_OVERRIDES.get(
|
||||
stream_details['stream_video_resolution'],
|
||||
stream_details['stream_video_resolution'] + (video_details['stream_video_scan_type'][:1] or 'p'))
|
||||
|
||||
# Get the quality profile
|
||||
if media_type in ('movie', 'episode', 'clip') and 'stream_bitrate' in stream_details:
|
||||
if sync_id:
|
||||
@@ -1945,8 +1995,7 @@ class PmsConnect(object):
|
||||
if stream_details['optimized_version']:
|
||||
source_bitrate = helpers.cast_to_int(source_media_details.get('bitrate'))
|
||||
optimized_version_profile = '{} Mbps {}'.format(round(source_bitrate / 1000.0, 1),
|
||||
plexpy.common.VIDEO_RESOLUTION_OVERRIDES.get(source_media_details['video_resolution'],
|
||||
source_media_details['video_resolution']))
|
||||
source_media_details['video_full_resolution'])
|
||||
else:
|
||||
optimized_version_profile = ''
|
||||
|
||||
@@ -2467,7 +2516,7 @@ class PmsConnect(object):
|
||||
media_info = {'container': helpers.get_xml_attr(media, 'container'),
|
||||
'bitrate': helpers.get_xml_attr(media, 'bitrate'),
|
||||
'video_codec': helpers.get_xml_attr(media, 'videoCodec'),
|
||||
'video_resolution': helpers.get_xml_attr(media, 'videoResolution'),
|
||||
'video_resolution': helpers.get_xml_attr(media, 'videoResolution').lower(),
|
||||
'video_framerate': helpers.get_xml_attr(media, 'videoFrameRate'),
|
||||
'audio_codec': helpers.get_xml_attr(media, 'audioCodec'),
|
||||
'audio_channels': helpers.get_xml_attr(media, 'audioChannels'),
|
||||
|
@@ -1,2 +1,2 @@
|
||||
PLEXPY_BRANCH = "master"
|
||||
PLEXPY_RELEASE_VERSION = "v2.1.34"
|
||||
PLEXPY_BRANCH = "beta"
|
||||
PLEXPY_RELEASE_VERSION = "v2.1.36-beta"
|
||||
|
@@ -2857,9 +2857,6 @@ class WebInterface(object):
|
||||
else:
|
||||
kwargs['http_password'] = plexpy.CONFIG.HTTP_PASSWORD
|
||||
|
||||
# Flag to refresh JWT uuid to log out clients
|
||||
kwargs['jwt_update_secret'] = True
|
||||
|
||||
elif kwargs['http_password'] and kwargs.get('http_hash_password'):
|
||||
kwargs['http_password'] = make_hash(kwargs['http_password'])
|
||||
kwargs['http_hashed_password'] = 1
|
||||
@@ -2869,6 +2866,10 @@ class WebInterface(object):
|
||||
|
||||
elif not kwargs.get('http_hash_password'):
|
||||
kwargs['http_hashed_password'] = 0
|
||||
|
||||
# Flag to refresh JWT uuid to log out clients
|
||||
kwargs['jwt_update_secret'] = True
|
||||
|
||||
else:
|
||||
kwargs['http_hashed_password'] = 0
|
||||
|
||||
@@ -4558,6 +4559,7 @@ class WebInterface(object):
|
||||
"Drama",
|
||||
"Fantasy"
|
||||
],
|
||||
"grandparent_guid": "com.plexapp.agents.thetvdb://121361?lang=en",
|
||||
"grandparent_rating_key": "1219",
|
||||
"grandparent_thumb": "/library/metadata/1219/thumb/1462175063",
|
||||
"grandparent_title": "Game of Thrones",
|
||||
@@ -4598,6 +4600,7 @@ class WebInterface(object):
|
||||
"video_language_code": "",
|
||||
"video_profile": "high",
|
||||
"video_ref_frames": "4",
|
||||
"video_scan_type": "progressive",
|
||||
"video_width": "1920",
|
||||
"selected": 0
|
||||
},
|
||||
@@ -4632,6 +4635,7 @@ class WebInterface(object):
|
||||
],
|
||||
"video_codec": "h264",
|
||||
"video_framerate": "24p",
|
||||
"video_full_resolution": "1080p",
|
||||
"video_profile": "high",
|
||||
"video_resolution": "1080",
|
||||
"width": "1920"
|
||||
@@ -4640,6 +4644,7 @@ class WebInterface(object):
|
||||
"media_type": "episode",
|
||||
"original_title": "",
|
||||
"originally_available_at": "2016-04-24",
|
||||
"parent_guid": "com.plexapp.agents.thetvdb://121361/6?lang=en",
|
||||
"parent_media_index": "6",
|
||||
"parent_rating_key": "153036",
|
||||
"parent_thumb": "/library/metadata/153036/thumb/1462175062",
|
||||
@@ -4950,6 +4955,7 @@ class WebInterface(object):
|
||||
"Drama",
|
||||
"Fantasy"
|
||||
],
|
||||
"grandparent_guid": "com.plexapp.agents.thetvdb://121361?lang=en",
|
||||
"grandparent_rating_key": "1219",
|
||||
"grandparent_thumb": "/library/metadata/1219/thumb/1503306930",
|
||||
"grandparent_title": "Game of Thrones",
|
||||
@@ -4977,6 +4983,7 @@ class WebInterface(object):
|
||||
"optimized_version_title": "",
|
||||
"originally_available_at": "2016-04-24",
|
||||
"original_title": "",
|
||||
"parent_guid": "com.plexapp.agents.thetvdb://121361/6?lang=en",
|
||||
"parent_media_index": "6",
|
||||
"parent_rating_key": "153036",
|
||||
"parent_thumb": "/library/metadata/153036/thumb/1503889210",
|
||||
@@ -5041,7 +5048,9 @@ class WebInterface(object):
|
||||
"stream_video_language": "",
|
||||
"stream_video_language_code": "",
|
||||
"stream_video_ref_frames": "4",
|
||||
"stream_video_full_resolution": "1080p",
|
||||
"stream_video_resolution": "1080",
|
||||
"stream_video_scan_type": "progressive",
|
||||
"stream_video_width": "1920",
|
||||
"studio": "HBO",
|
||||
"subtitle_codec": "",
|
||||
@@ -5094,12 +5103,14 @@ class WebInterface(object):
|
||||
"video_decision": "direct play",
|
||||
"video_frame_rate": "23.976",
|
||||
"video_framerate": "24p",
|
||||
"video_full_resolution": "1080p",
|
||||
"video_height": "1078",
|
||||
"video_language": "",
|
||||
"video_language_code": "",
|
||||
"video_profile": "high",
|
||||
"video_ref_frames": "4",
|
||||
"video_resolution": "1080",
|
||||
"video_scan_type": "progressive",
|
||||
"video_width": "1920",
|
||||
"view_offset": "1000",
|
||||
"width": "1920",
|
||||
|
Reference in New Issue
Block a user