mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-06 05:01:14 -07:00
Merge b447c37774
into 9a6253d775
This commit is contained in:
commit
c4a1c92128
9 changed files with 241 additions and 63 deletions
|
@ -2941,6 +2941,12 @@ a .home-platforms-list-cover-face:hover
|
|||
max-width: 1750px;
|
||||
display: flow-root;
|
||||
}
|
||||
.table-card-header.spaced {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
align-content: center;
|
||||
}
|
||||
.table-card-back td {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
@ -2952,6 +2958,18 @@ a .home-platforms-list-cover-face:hover
|
|||
font-weight: bold;
|
||||
line-height: 34px;
|
||||
}
|
||||
.info-bar {
|
||||
display: inline;
|
||||
}
|
||||
.info-element {
|
||||
display: inline-block;
|
||||
border-radius: 1rem;
|
||||
border: 0.2rem solid #242424;
|
||||
padding: 0.7rem;
|
||||
background-color: #3B3B3B;
|
||||
font-style: italic;
|
||||
color: #676767;
|
||||
}
|
||||
.button-bar {
|
||||
float: right;
|
||||
}
|
||||
|
|
|
@ -202,6 +202,30 @@ libraries_list_table_options = {
|
|||
"searchable": false,
|
||||
"width": "10%",
|
||||
"className": "no-wrap"
|
||||
},
|
||||
{
|
||||
"targets": [11],
|
||||
"data": "total_storage",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData !== null && cellData !== '') {
|
||||
$(td).html(humanFileSize(cellData));
|
||||
}
|
||||
},
|
||||
"searchable": false,
|
||||
"width": "10%",
|
||||
"className": "no-wrap"
|
||||
},
|
||||
{
|
||||
"targets": [12],
|
||||
"data": "total_duration",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData !== null && cellData !== '') {
|
||||
$(td).html(humanDuration(cellData));
|
||||
}
|
||||
},
|
||||
"searchable": false,
|
||||
"width": "10%",
|
||||
"className": "no-wrap"
|
||||
}
|
||||
|
||||
],
|
||||
|
|
|
@ -224,6 +224,22 @@ media_info_table_options = {
|
|||
},
|
||||
{
|
||||
"targets": [10],
|
||||
"data": "duration",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData !== null && cellData !== '' && cellData !== 0) {
|
||||
$(td).html(humanDuration(cellData));
|
||||
} else {
|
||||
if (rowData['section_type'] != 'photo' && get_file_sizes != null) {
|
||||
get_file_sizes = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
"width": "7%",
|
||||
"className": "no-wrap",
|
||||
"searchable": false
|
||||
},
|
||||
{
|
||||
"targets": [11],
|
||||
"data": "last_played",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData !== null && cellData !== '') {
|
||||
|
@ -236,7 +252,7 @@ media_info_table_options = {
|
|||
"searchable": false
|
||||
},
|
||||
{
|
||||
"targets": [11],
|
||||
"targets": [12],
|
||||
"data": "play_count",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData !== null && cellData !== '') {
|
||||
|
@ -457,6 +473,7 @@ function childTableFormatMedia(rowData) {
|
|||
'<th align="left" id="audio_codec">Audio Codec</th>' +
|
||||
'<th align="left" id="audio_channels">Audio Channels</th>' +
|
||||
'<th align="left" id="file_size">File Size</th>' +
|
||||
'<th align="left" id="duration">Duration</th>' +
|
||||
'<th align="left" id="last_played">Last Played</th>' +
|
||||
'<th align="left" id="total_plays">Total Plays</th>' +
|
||||
'</tr>' +
|
||||
|
|
|
@ -41,6 +41,8 @@
|
|||
<th align="left" id="last_played">Last Played</th>
|
||||
<th align="left" id="total_plays">Total Plays</th>
|
||||
<th align="left" id="total_duration">Total Played Duration</th>
|
||||
<th align="left" id="total_storage">Total Storage</th>
|
||||
<th align="left" id="total_runtime">Total Runtime</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
|
|
@ -271,7 +271,7 @@ DOCUMENTATION :: END
|
|||
You may leave this page and check back later.
|
||||
</div>
|
||||
% endif
|
||||
<div class='table-card-header'>
|
||||
<div class='table-card-header spaced'>
|
||||
<div class="header-bar">
|
||||
<span>
|
||||
<i class="fa fa-info-circle"></i> Media Info for <strong>
|
||||
|
@ -279,6 +279,14 @@ DOCUMENTATION :: END
|
|||
</strong>
|
||||
</span>
|
||||
</div>
|
||||
<div class="info-bar">
|
||||
<div class="info-element">
|
||||
<span>Total File Size: <strong><span id="info-element-total-storage" /></strong></span>
|
||||
</div>
|
||||
<div class="info-element">
|
||||
<span>Total Media Runtime: <strong><span id="info-element-total-runtime" /></strong></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="button-bar">
|
||||
% if _session['user_group'] == 'admin':
|
||||
<div class="btn-group">
|
||||
|
@ -310,6 +318,7 @@ DOCUMENTATION :: END
|
|||
<th align="left" id="audio_codec">Audio Codec</th>
|
||||
<th align="left" id="audio_channels">Audio Channels</th>
|
||||
<th align="left" id="file_size">File Size</th>
|
||||
<th align="left" id="duration">Duration</th>
|
||||
<th align="left" id="last_played">Last Played</th>
|
||||
<th align="left" id="total_plays">Total Plays</th>
|
||||
</tr>
|
||||
|
@ -779,6 +788,22 @@ DOCUMENTATION :: END
|
|||
clearSearchButton('media_info_table-SID-${data["section_id"]}', media_info_table);
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
loadLibraryMediaStats();
|
||||
});
|
||||
|
||||
function loadLibraryMediaStats(refresh) {
|
||||
// Populate media stats
|
||||
$.ajax({
|
||||
url: 'get_library_media_stats',
|
||||
data: { section_id: section_id, refresh: refresh },
|
||||
complete: function(xhr, status) {
|
||||
$("#info-element-total-runtime").html(humanDuration(xhr.responseJSON.total_duration));
|
||||
$("#info-element-total-storage").html(humanFileSize(xhr.responseJSON.total_storage));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$('#nav-tabs-mediainfo').on('shown.bs.tab', function() {
|
||||
if (typeof(media_info_table) === 'undefined') {
|
||||
loadMediaInfoTable();
|
||||
|
@ -790,6 +815,7 @@ DOCUMENTATION :: END
|
|||
refresh_table = true;
|
||||
refresh_child_tables = true;
|
||||
media_info_table.draw();
|
||||
loadLibraryMediaStats(true);
|
||||
refresh_table = false;
|
||||
});
|
||||
|
||||
|
|
|
@ -75,6 +75,8 @@ def refresh_libraries():
|
|||
if result == 'insert':
|
||||
new_keys.append(section['section_id'])
|
||||
|
||||
get_library_media_stats(section_id=section['section_id'], refresh=True)
|
||||
|
||||
add_live_tv_library(refresh=True)
|
||||
|
||||
query = "UPDATE library_sections SET is_active = 0 WHERE server_id != ? OR " \
|
||||
|
@ -125,6 +127,44 @@ def has_library_type(section_type):
|
|||
result = monitor_db.select_single(query=query, args=args)
|
||||
return bool(result)
|
||||
|
||||
def get_library_media_stats(section_id=None, refresh=False):
|
||||
plex = Plex(token=session.get_session_user_token())
|
||||
libraries = Libraries()
|
||||
|
||||
default_return = {
|
||||
'total_size': 0,
|
||||
'total_storage': 0,
|
||||
'total_duration': 0
|
||||
}
|
||||
|
||||
if section_id and not str(section_id).isdigit():
|
||||
logger.warn("Tautulli Libraries :: Library media stats requested but invalid section_id provided.")
|
||||
return default_return
|
||||
|
||||
if not session.allow_session_library(section_id):
|
||||
logger.warn("Tautulli Libraries :: Library media stats requested but library is not allowed for this session.")
|
||||
return default_return
|
||||
|
||||
# Import media info cache from json file
|
||||
_, cached_library_media_stats, _ = libraries._load_data_from_cache(section_id=section_id, path='media_stats')
|
||||
|
||||
_live_data = not cached_library_media_stats or refresh
|
||||
if _live_data:
|
||||
library = plex.get_library(section_id)
|
||||
|
||||
if library is None:
|
||||
logger.warn("Tautulli Libraries :: Library media stats requested but no library was found section_id %s.", section_id)
|
||||
return default_return
|
||||
|
||||
library_media_stats = {
|
||||
'total_size': library.totalSize if _live_data else cached_library_media_stats.get('total_size', 0),
|
||||
'total_storage': library.totalStorage if _live_data else cached_library_media_stats.get('total_storage', 0),
|
||||
'total_duration': library.totalDuration if _live_data else cached_library_media_stats.get('total_duration', 0)
|
||||
}
|
||||
|
||||
libraries._save_data_to_cache(section_id=section_id, rows=library_media_stats, path='media_stats')
|
||||
|
||||
return library_media_stats
|
||||
|
||||
def get_collections(section_id=None):
|
||||
plex = Plex(token=session.get_session_user_token())
|
||||
|
@ -391,18 +431,23 @@ class Libraries(object):
|
|||
else:
|
||||
library_art = item['library_art']
|
||||
|
||||
library_media_stats = get_library_media_stats(item['section_id'])
|
||||
|
||||
row = {'row_id': item['row_id'],
|
||||
'server_id': item['server_id'],
|
||||
'section_id': item['section_id'],
|
||||
'section_name': item['section_name'],
|
||||
'section_type': item['section_type'],
|
||||
'count': item['count'],
|
||||
'total_size': library_media_stats['total_size'],
|
||||
'parent_count': item['parent_count'],
|
||||
'child_count': item['child_count'],
|
||||
'library_thumb': library_thumb,
|
||||
'library_art': library_art,
|
||||
'plays': item['plays'],
|
||||
'total_storage': library_media_stats['total_storage'],
|
||||
'duration': item['duration'],
|
||||
'total_duration': library_media_stats['total_duration'],
|
||||
'last_accessed': item['last_accessed'],
|
||||
'history_row_id': item['history_row_id'],
|
||||
'last_played': item['last_played'],
|
||||
|
@ -441,6 +486,7 @@ class Libraries(object):
|
|||
'data': [],
|
||||
'filtered_file_size': 0,
|
||||
'total_file_size': 0,
|
||||
'total_media_duration': 0,
|
||||
'last_refreshed': None}
|
||||
|
||||
if not session.allow_session_library(section_id):
|
||||
|
@ -497,10 +543,13 @@ class Libraries(object):
|
|||
'play_count': item['play_count']}
|
||||
|
||||
# Import media info cache from json file
|
||||
cache_time, rows, library_count = self._load_media_info_cache(section_id=section_id, rating_key=rating_key)
|
||||
cache_time, rows, library_count = self._load_data_from_cache(section_id=section_id, rating_key=rating_key, path='media_info')
|
||||
|
||||
# Check if duration is also included in cache else refresh cache to prevent update issues
|
||||
refresh = refresh if None not in {d.get('duration') for d in rows} else True
|
||||
|
||||
# If no cache was imported, get all library children items
|
||||
cached_items = {d['rating_key']: d['file_size'] for d in rows} if not refresh else {}
|
||||
cached_items = {d['rating_key']: [d['file_size'], d['duration']] for d in rows} if not refresh else {}
|
||||
|
||||
if refresh or not rows:
|
||||
pms_connect = pmsconnect.PmsConnect()
|
||||
|
@ -525,8 +574,10 @@ class Libraries(object):
|
|||
for item in children_list:
|
||||
## TODO: Check list of media info items, currently only grabs first item
|
||||
|
||||
cached_file_size = cached_items.get(item['rating_key'], None)
|
||||
file_size = cached_file_size if cached_file_size else item.get('file_size', '')
|
||||
cached_item_data = cached_items.get(item['rating_key'], None)
|
||||
|
||||
file_size = cached_item_data['file_size'] if cached_item_data else item.get('file_size', '')
|
||||
duration = cached_item_data['duration'] if cached_item_data else item['duration']
|
||||
|
||||
row = {'section_id': library_details['section_id'],
|
||||
'section_type': library_details['section_type'],
|
||||
|
@ -548,7 +599,8 @@ class Libraries(object):
|
|||
'video_framerate': item.get('video_framerate', ''),
|
||||
'audio_codec': item.get('audio_codec', ''),
|
||||
'audio_channels': item.get('audio_channels', ''),
|
||||
'file_size': file_size
|
||||
'file_size': file_size,
|
||||
'duration': duration
|
||||
}
|
||||
new_rows.append(row)
|
||||
|
||||
|
@ -557,7 +609,7 @@ class Libraries(object):
|
|||
return default_return
|
||||
|
||||
# Cache the media info to a json file
|
||||
self._save_media_info_cache(section_id=section_id, rating_key=rating_key, rows=rows)
|
||||
self._save_data_to_cache(section_id=section_id, rating_key=rating_key, rows=rows, path='media_info')
|
||||
|
||||
# Update the last_played and play_count
|
||||
for item in rows:
|
||||
|
@ -606,6 +658,7 @@ class Libraries(object):
|
|||
results = sorted(results, key=lambda k: k[sort_key].lower(), reverse=reverse)
|
||||
|
||||
total_file_size = sum([helpers.cast_to_int(d['file_size']) for d in results])
|
||||
total_media_duration = sum([helpers.cast_to_int(d['duration']) for d in results])
|
||||
|
||||
# Paginate results
|
||||
results = results[json_data['start']:(json_data['start'] + json_data['length'])]
|
||||
|
@ -619,6 +672,7 @@ class Libraries(object):
|
|||
'draw': int(json_data['draw']),
|
||||
'filtered_file_size': filtered_file_size,
|
||||
'total_file_size': total_file_size,
|
||||
'total_media_duration': total_media_duration,
|
||||
'last_refreshed': cache_time
|
||||
}
|
||||
|
||||
|
@ -644,19 +698,20 @@ class Libraries(object):
|
|||
return False
|
||||
|
||||
# Import media info cache from json file
|
||||
_, rows, _ = self._load_media_info_cache(section_id=section_id, rating_key=rating_key)
|
||||
_, rows, _ = self._load_data_from_cache(section_id=section_id, rating_key=rating_key, path='media_info')
|
||||
|
||||
# Get the total file size for each item
|
||||
if rating_key:
|
||||
logger.debug("Tautulli Libraries :: Getting file sizes for rating_key %s." % rating_key)
|
||||
elif section_id:
|
||||
logger.debug("Tautulli Libraries :: Fetting file sizes for section_id %s." % section_id)
|
||||
logger.debug("Tautulli Libraries :: Fetching file sizes for section_id %s." % section_id)
|
||||
|
||||
pms_connect = pmsconnect.PmsConnect()
|
||||
|
||||
for item in rows:
|
||||
if item['rating_key'] and not item['file_size']:
|
||||
if item['rating_key'] and (not item['file_size'] or not item['duration']):
|
||||
file_size = 0
|
||||
duration = 0
|
||||
|
||||
metadata = pms_connect.get_metadata_children_details(rating_key=item['rating_key'],
|
||||
get_children=True,
|
||||
|
@ -673,11 +728,13 @@ class Libraries(object):
|
|||
media_info['parts'][0])
|
||||
|
||||
file_size += helpers.cast_to_int(media_part_info.get('file_size', 0))
|
||||
duration += helpers.cast_to_int(child_metadata.get('duration', 0))
|
||||
|
||||
item['file_size'] = file_size
|
||||
item['duration'] = duration
|
||||
|
||||
# Cache the media info to a json file
|
||||
self._save_media_info_cache(section_id=section_id, rating_key=rating_key, rows=rows)
|
||||
self._save_data_to_cache(section_id=section_id, rating_key=rating_key, rows=rows, path='media_info')
|
||||
|
||||
if rating_key:
|
||||
logger.debug("Tautulli Libraries :: File sizes updated for rating_key %s." % rating_key)
|
||||
|
@ -686,67 +743,51 @@ class Libraries(object):
|
|||
|
||||
return True
|
||||
|
||||
def _load_media_info_cache(self, section_id=None, rating_key=None):
|
||||
def _load_data_from_cache(self, section_id=None, rating_key=None, path=None):
|
||||
cache_time = None
|
||||
rows = []
|
||||
library_count = 0
|
||||
|
||||
# Import media info cache from json file
|
||||
if rating_key:
|
||||
try:
|
||||
inFilePath = os.path.join(plexpy.CONFIG.CACHE_DIR,'media_info_%s-%s.json' % (section_id, rating_key))
|
||||
with open(inFilePath, 'r') as inFile:
|
||||
data = json.load(inFile)
|
||||
if isinstance(data, dict):
|
||||
cache_time = data['last_refreshed']
|
||||
rows = data['rows']
|
||||
else:
|
||||
rows = data
|
||||
library_count = len(rows)
|
||||
logger.debug("Tautulli Libraries :: Loaded media info from cache for rating_key %s (%s items)." % (rating_key, library_count))
|
||||
except IOError as e:
|
||||
logger.debug("Tautulli Libraries :: No media info cache for rating_key %s." % rating_key)
|
||||
section_id = str(section_id) if section_id else section_id
|
||||
rating_key = str(rating_key) if rating_key else rating_key
|
||||
|
||||
elif section_id:
|
||||
try:
|
||||
inFilePath = os.path.join(plexpy.CONFIG.CACHE_DIR,'media_info_%s.json' % section_id)
|
||||
with open(inFilePath, 'r') as inFile:
|
||||
data = json.load(inFile)
|
||||
if isinstance(data, dict):
|
||||
cache_time = data['last_refreshed']
|
||||
rows = data['rows']
|
||||
else:
|
||||
rows = data
|
||||
library_count = len(rows)
|
||||
logger.debug("Tautulli Libraries :: Loaded media info from cache for section_id %s (%s items)." % (section_id, library_count))
|
||||
except IOError as e:
|
||||
logger.debug("Tautulli Libraries :: No media info cache for section_id %s." % section_id)
|
||||
# Import data cache from json file
|
||||
try:
|
||||
inFilePath = os.path.join(plexpy.CONFIG.CACHE_DIR, (path + '_%s%s' % (section_id, ('-' + rating_key) if rating_key else '')))
|
||||
with open(inFilePath, 'r') as inFile:
|
||||
data = json.load(inFile)
|
||||
if isinstance(data, dict):
|
||||
cache_time = data['last_refreshed']
|
||||
rows = data['rows']
|
||||
else:
|
||||
rows = data
|
||||
library_count = len(rows)
|
||||
logger.debug("Tautulli Libraries :: Loaded %s from cache for section_id %s%s (%s items)." %
|
||||
(path, section_id, (' and rating key ' + rating_key) if rating_key else '', library_count))
|
||||
except IOError as e:
|
||||
logger.debug("Tautulli Libraries :: No media info cache for section_id %s%s." %
|
||||
(section_id, (' and rating key ' + rating_key) if rating_key else ''))
|
||||
|
||||
return cache_time, rows, library_count
|
||||
|
||||
def _save_media_info_cache(self, section_id=None, rating_key=None, rows=None):
|
||||
def _save_data_to_cache(self, section_id, rating_key=None, rows=None, path=None):
|
||||
cache_time = helpers.timestamp()
|
||||
|
||||
if rows is None:
|
||||
rows = []
|
||||
|
||||
if rating_key:
|
||||
try:
|
||||
outFilePath = os.path.join(plexpy.CONFIG.CACHE_DIR,'media_info_%s-%s.json' % (section_id, rating_key))
|
||||
with open(outFilePath, 'w') as outFile:
|
||||
json.dump({'last_refreshed': cache_time, 'rows': rows}, outFile)
|
||||
logger.debug("Tautulli Libraries :: Saved media info cache for rating_key %s." % rating_key)
|
||||
except IOError as e:
|
||||
logger.debug("Tautulli Libraries :: Unable to create cache file for rating_key %s." % rating_key)
|
||||
|
||||
elif section_id:
|
||||
try:
|
||||
outFilePath = os.path.join(plexpy.CONFIG.CACHE_DIR,'media_info_%s.json' % section_id)
|
||||
with open(outFilePath, 'w') as outFile:
|
||||
json.dump({'last_refreshed': cache_time, 'rows': rows}, outFile)
|
||||
logger.debug("Tautulli Libraries :: Saved media info cache for section_id %s." % section_id)
|
||||
except IOError as e:
|
||||
logger.debug("Tautulli Libraries :: Unable to create cache file for section_id %s." % section_id)
|
||||
section_id = str(section_id) if section_id else section_id
|
||||
rating_key = str(rating_key) if rating_key else rating_key
|
||||
|
||||
try:
|
||||
outFilePath = os.path.join(plexpy.CONFIG.CACHE_DIR, (path + '_%s%s' % (section_id, ('-' + rating_key) if rating_key else '')))
|
||||
with open(outFilePath, 'w') as outFile:
|
||||
json.dump({'last_refreshed': cache_time, 'rows': rows}, outFile)
|
||||
logger.debug("Tautulli Libraries :: Saved %s cache for section_id %s%s." %
|
||||
(path, section_id, (' and rating key ' + rating_key) if rating_key else ''))
|
||||
except IOError as e:
|
||||
logger.debug("Tautulli Libraries :: Unable to create cache file for section_id %s%s with error %s." %
|
||||
(section_id, (' and rating key ' + rating_key) if rating_key else '', e))
|
||||
|
||||
def set_config(self, section_id=None, custom_thumb='', custom_art='',
|
||||
do_notify=1, keep_history=1, do_notify_created=1):
|
||||
|
|
|
@ -50,7 +50,14 @@ class Plex(object):
|
|||
self.PlexServer = PlexObject(url, token)
|
||||
|
||||
def get_library(self, section_id):
|
||||
return self.PlexServer.library.sectionByID(int(section_id))
|
||||
from plexapi.exceptions import NotFound
|
||||
|
||||
try:
|
||||
library = self.PlexServer.library.sectionByID(int(section_id))
|
||||
except NotFound:
|
||||
library = None
|
||||
|
||||
return library
|
||||
|
||||
def get_library_items(self, section_id):
|
||||
return self.get_library(section_id).all()
|
||||
|
|
|
@ -2912,7 +2912,8 @@ class PmsConnect(object):
|
|||
'thumb': helpers.get_xml_attr(item, 'thumb'),
|
||||
'parent_thumb': helpers.get_xml_attr(item, 'thumb'),
|
||||
'grandparent_thumb': helpers.get_xml_attr(item, 'grandparentThumb'),
|
||||
'added_at': helpers.get_xml_attr(item, 'addedAt')
|
||||
'added_at': helpers.get_xml_attr(item, 'addedAt'),
|
||||
'duration': helpers.get_xml_attr(item, 'duration') if section_type in ('movie', 'episode', 'track') else 0
|
||||
}
|
||||
|
||||
if get_media_info:
|
||||
|
|
|
@ -498,6 +498,9 @@ class WebInterface(object):
|
|||
"section_type": "Show",
|
||||
"server_id": "ds48g4r354a8v9byrrtr697g3g79w",
|
||||
"thumb": "/library/metadata/153036/thumb/1462175062",
|
||||
"total_duration": 3048551210,
|
||||
"total_size": 62,
|
||||
"total_storage": 1866078986762,
|
||||
"year": 2016
|
||||
},
|
||||
{...},
|
||||
|
@ -519,7 +522,9 @@ class WebInterface(object):
|
|||
("last_accessed", True, False),
|
||||
("last_played", True, True),
|
||||
("plays", True, False),
|
||||
("duration", True, False)]
|
||||
("duration", True, False),
|
||||
("total_storage", True, False),
|
||||
("total_duration", True, False)]
|
||||
kwargs['json_data'] = build_datatables_json(kwargs, dt_columns, "section_name")
|
||||
|
||||
grouping = helpers.bool_true(grouping, return_none=True)
|
||||
|
@ -653,6 +658,40 @@ class WebInterface(object):
|
|||
except:
|
||||
return "Failed to update library."
|
||||
|
||||
@cherrypy.expose
|
||||
@cherrypy.tools.json_out()
|
||||
@requireAuth(member_of("admin"))
|
||||
@addtoapi()
|
||||
def get_library_media_stats(self, section_id=None, refresh=''):
|
||||
""" Get the media stats of a library section on Tautulli.
|
||||
|
||||
```
|
||||
Required parameters:
|
||||
section_id (str): The id of the Plex library section
|
||||
refresh (str): "true" to force a refresh of the stats
|
||||
|
||||
Optional parameters:
|
||||
None
|
||||
|
||||
Returns:
|
||||
{
|
||||
"total_duration": 3048551210,
|
||||
"total_size": 62,
|
||||
"total_storage": 1866078986762
|
||||
}
|
||||
```
|
||||
"""
|
||||
|
||||
if helpers.bool_true(refresh):
|
||||
refresh = True
|
||||
else:
|
||||
refresh = False
|
||||
|
||||
logger.info("Getting library media stats for section %s.", section_id)
|
||||
result = libraries.get_library_media_stats(section_id=section_id, refresh=refresh)
|
||||
|
||||
return result
|
||||
|
||||
@cherrypy.expose
|
||||
@requireAuth()
|
||||
def library_watch_time_stats(self, section_id=None, **kwargs):
|
||||
|
@ -756,12 +795,14 @@ class WebInterface(object):
|
|||
"recordsFiltered": 82,
|
||||
"filtered_file_size": 2616760056742,
|
||||
"total_file_size": 2616760056742,
|
||||
"total_media_duration": 7947375522,
|
||||
"data":
|
||||
[{"added_at": "1403553078",
|
||||
"audio_channels": "",
|
||||
"audio_codec": "",
|
||||
"bitrate": "",
|
||||
"container": "",
|
||||
"duration": "",
|
||||
"file_size": 253660175293,
|
||||
"grandparent_rating_key": "",
|
||||
"last_played": 1462380698,
|
||||
|
@ -804,6 +845,7 @@ class WebInterface(object):
|
|||
("video_framerate", True, True),
|
||||
("audio_codec", True, True),
|
||||
("audio_channels", True, True),
|
||||
("duration", True, False),
|
||||
("file_size", True, False),
|
||||
("last_played", True, False),
|
||||
("play_count", True, False)]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue