<%inherit file="base.html"/>

<%def name="headIncludes()">
<link href="${http_root}css/jquery.scrollbar.css" rel="stylesheet">
</%def>

<%def name="body()">
<% from plexpy import PLEX_SERVER_UP %>
<div class="container-fluid">
    % for section in config['home_sections']:
    % if section == 'current_activity':
    <div class="row">
        <div class="col-md-12">
            <div class="padded-header" id="current-activity-header">
                <h3><span id="sessions-xml">Activity</span> &nbsp;&nbsp;
                    <small>
                        <span id="currentActivityHeader" style="display: none;">
                            Sessions: <span id="currentActivityHeader-streams"></span> |
                            Bandwidth: <span id="currentActivityHeader-bandwidth"></span>
                            <span id="currentActivityHeader-bandwidth-tooltip" data-toggle="tooltip" title="Streaming Brain Estimate (Reserved Bandwidth)"><i class="fa fa-info-circle"></i></span>
                        </span>
                    </small>
                </h3>
            </div>
            <div id="currentActivity">
                % if PLEX_SERVER_UP:
                <div class="text-muted" id="dashboard-checking-activity"><i class="fa fa-refresh fa-spin"></i>&nbsp; Checking for activity...</div>
                % elif config['pms_is_cloud']:
                <div id="dashboard-no-activity" class="text-muted">Plex Cloud server is sleeping.</div>
                % elif not config['first_run_complete']:
                <div id="dashboard-no-activity" class="text-muted">The Tautulli setup wizard has not been completed. Please click <a href="welcome">here</a> to go to the setup wizard.</div>
                % else:
                <div class="text-muted" id="dashboard-checking-activity"><i class="fa fa-refresh fa-spin"></i>&nbsp; Tautulli is connecting to the Plex server...</div>
                % endif
            </div>
        </div>
    </div>
    % elif section == 'watch_stats':
    <div class="row">
        <div class="col-md-12">
            <div class="home-padded-header padded-header">
                <h3 class="pull-left">Watch Statistics</h3>
                <div class="button-bar">
                    <div class="btn-group pull-left" data-toggle="buttons" id="watch-stats-toggles" style="margin-right: 3px">
                        <label class="btn btn-dark btn-filter">
                            <input type="radio" class="watched-stats-toggle" name="watched-stats-type" id="watched-stats-plays" value="plays" autocomplete="off"> Play Count
                        </label>
                        <label class="btn btn-dark btn-filter">
                            <input type="radio" class="watched-stats-toggle" name="watched-stats-type" id="watched-stats-duration" value="duration" autocomplete="off"> Play Duration
                        </label>
                    </div>
                    <div class="input-group pull-left" style="width: 1px; margin-right: 3px" id="watched-stats-days-selection">
                        <span class="input-group-addon btn-dark inactive">Last</span>
                        <input type="number" class="form-control number-input" name="watched-stats-days" id="watched-stats-days" value="30" min="1" data-default="30" data-toggle="tooltip" title="Min: 1 day" />
                        <span class="input-group-addon btn-dark inactive">days</span>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <div class="row">
        <div class="col-md-12">
            <div id="home-stats" class="home-platforms">
                <div class="text-muted"><i class="fa fa-refresh fa-spin"></i>&nbsp; Loading stats...</div>
                <br>
            </div>
        </div>
    </div>
    % elif section == 'library_stats':
    <div class="row">
        <div class="col-md-12">
            <div class="home-padded-header padded-header" id="library-statistics-header">
                <h3 class="pull-left">Library Statistics</h3>
                <div class="button-bar">
                    <span class="btn btn-dark active" style="cursor: default">${config['pms_name']}</span>
                </div>
            </div>
        </div>
    </div>
    <div class="row">
        <div class="col-md-12">
            <div id="library-stats" class="library-platforms">
                <div class="text-muted"><i class="fa fa-refresh fa-spin"></i>&nbsp; Loading stats...</div>
                <br>
            </div>
        </div>
    </div>
    % elif section == 'recently_added':
    <div class="row">
        <div class="col-md-12">
            <div class="home-padded-header padded-header">
                <h3 class="pull-left"><span id="recently-added-xml">Recently Added</span></h3>
                <ul class="nav nav-header nav-dashboard pull-right" style="margin-top: -3px;">
                    <li>
                        <a href="#" id="recently-added-page-left" class="paginate-added btn-gray disabled" data-id="-1"><i class="fa fa-lg fa-chevron-left"></i></a>
                    </li>
                    <li>
                        <a href="#" id="recently-added-page-right" class="paginate-added btn-gray disabled" data-id="+1"><i class="fa fa-lg fa-chevron-right"></i></a>
                    </li>
                </ul>
                <div class="button-bar">
                    <div class="btn-group pull-left" data-toggle="buttons" id="recently-added-toggles" style="margin-right: 3px">
                        <label class="btn btn-dark btn-filter" id="recently-added-label-all">
                            <input type="radio" name="recently-added-toggle" id="recently-added-toggle-all" value="all" autocomplete="off"> All
                        </label>
                        <label class="btn btn-dark btn-filter" id="recently-added-label-movies">
                            <input type="radio" name="recently-added-toggle" id="recently-added-toggle-movie" value="movie" autocomplete="off"> Movies
                        </label>
                        <label class="btn btn-dark btn-filter" id="recently-added-label-tv">
                            <input type="radio" name="recently-added-toggle" id="recently-added-toggle-show" value="show" autocomplete="off"> TV Shows
                        </label>
                        <label class="btn btn-dark btn-filter" id="recently-added-label-music">
                            <input type="radio" name="recently-added-toggle" id="recently-added-toggle-artist" value="artist" autocomplete="off"> Music
                        </label>
                        <label class="btn btn-dark btn-filter" id="recently-added-label-other_video">
                            <input type="radio" name="recently-added-toggle" id="recently-added-toggle-other_video" value="other_video" autocomplete="off"> Videos
                        </label>
                    </div>
                    <div class="input-group pull-left" style="width: 1px;" id="recently-added-count-selection">
                        <input type="number" class="form-control number-input" name="recently-added-count" id="recently-added-count" value="50" min="1" max="50" data-default="50" data-toggle="tooltip" title="Min: 1 item<br>Max: 50 items" />
                        <span class="input-group-addon btn-dark inactive">items</span>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <div class="row">
        <div class="col-md-12">
            <div id="recentlyAdded" style="margin-right: -15px;">
                % if PLEX_SERVER_UP:
                <div id="dashboard-checking-recently-added" class="text-muted"><i class="fa fa-refresh fa-spin"></i>&nbsp; Looking for new items...</div>
                % elif config['pms_is_cloud']:
                <div class="text-muted">Plex Cloud server is sleeping.</div>
                % else:
                <div id="dashboard-no-recently-added" class="text-muted"><i class="fa fa-refresh fa-spin"></i>&nbsp; Tautulli is connecting to your Plex server...</div>
                % endif
            </div>
        </div>
    </div>
    % endif
    % endfor
</div>
</%def>

<%def name="modalIncludes()">

% if _session['user_group'] == 'admin' and config['update_show_changelog']:
<% from plexpy.common import RELEASE %>
<div id="changelog-modal" class="modal fade wide" tabindex="-1" role="dialog" aria-labelledby="changelog-modal">
    <div class="modal-dialog" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove"></i></button>
                <h4 class="modal-title">Tautulli Updated to <strong>${RELEASE}</strong></h4>
            </div>
            <div class="modal-body">
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-danger" data-target="#donate-modal" data-toggle="modal" style="float: left;"><i class="fa fa-fw fa-heart"></i> Donate</button>
                <input type="button" class="btn btn-bright" data-dismiss="modal" value="Close">
            </div>
        </div>
    </div>
</div>
% endif

% if _session['user_group'] == 'admin':
<div id="terminate-session-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="terminate-session-modal">
    <div class="modal-dialog" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove"></i></button>
                <h4 class="modal-title">Terminate Stream</h4>
            </div>
            <div class="modal-body" style="text-align: center;">
                <p>Are you sure you want to terminate this stream?</p>
                <p>
                    <strong>
                        <span id="terminate-user"></span><br />
                        <span id="terminate-title"></span><br />
                        <span id="terminate-subtitle"></span>
                    </strong>
                </p>
                <br />
                <label for="terminate-message">Terminate Message</label>
                <div class="row">
                    <div class="col-md-8" style="float: none; margin: 0 auto;">
                        <input type="text" class="form-control" id="terminate-message" name="terminate-message" value="" placeholder="The server owner has ended the stream." style="text-align: center;">
                    </div>
                </div>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-dark" data-dismiss="modal">Cancel</button>
                <button type="button" class="btn btn-danger btn-ok" data-dismiss="modal" id="confirm-terminate-session">Terminate</button>
            </div>
        </div>
    </div>
</div>
<div class="modal fade wide" id="raw-stream-info-modal" tabindex="-1" role="dialog" aria-labelledby="raw-stream-info-modal">
    <div class="modal-dialog" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove"></i></button>
                <h4 class="modal-title">Raw Stream Info: <strong><span id="raw-stream-info-title"></span> (<span id="raw-stream-info-user"></span>)</strong></h4>
            </div>
            <div class="modal-body">
                <pre id="raw-stream-info"></pre>
            </div>
            <div class="modal-footer">
                <input type="button" class="btn btn-bright" data-dismiss="modal" value="Close">
            </div>
        </div>
    </div>
</div>
% endif

<div class="modal fade" id="ip-info-modal" tabindex="-1" role="dialog" aria-labelledby="ip-info-modal">
</div>

</%def>

<%def name="javascriptIncludes()">
<script src="${http_root}js/jquery.scrollbar.min.js"></script>
<script src="${http_root}js/jquery.mousewheel.min.js"></script>
<script>
    var date_format = 'YYYY-MM-DD';
    var time_format = 'hh:mm a';
    $.ajax({
        url: 'get_date_formats',
        type: 'GET',
        success: function (data) {
            date_format = data.date_format;
            time_format = data.time_format;
        }
    });

    function lockScroll(elem) {
        $(elem).each(function (i, instance)  {
            var childHeight = $(instance).children('.scoller-content').height();
            var height = $(instance).height();
            var scrollHeight = $(instance).get(0).scrollHeight;

            if (childHeight > height) {
                $(instance).on('mousewheel', function(e, d) {
                    if(($(instance).scrollTop() >= (scrollHeight - height)) && d < 0 || ($(instance).scrollTop() <= 0) && d > 0) {
                        e.preventDefault();
                    }
                });
            }
        });
    }

    % if _session['user_group'] == 'admin':
    var msg_settings = ' Check the <a href="logs">logs</a> and verify your server connection in the <a href="settings#tab_tabs-plex_media_server">settings</a>.';
    % else:
    var msg_settings = '';
    % endif

    var error_msg = 'There was an error communicating with your Plex Server.' + msg_settings;

    % if 'current_activity' in config['home_sections'] or 'recently_added' in config['home_sections']:
    var server_status;
    server_status = setInterval(function() {
        $.getJSON('server_status', function (data) {
            if (data.connected === true) {
                clearInterval(server_status);
                % if 'current_activity' in config['home_sections']:
                $('#currentActivity').html('<div id="dashboard-checking-activity" class="text-muted"><i class="fa fa-refresh fa-spin"></i>&nbsp; Checking for activity...</div>');
                activityConnected();
                % endif
                % if 'recently_added' in config['home_sections']:
                $('#recentlyAdded').html('<div id="dashboard-checking-recently-added" class="text-muted"><i class="fa fa-refresh fa-spin"></i>&nbsp; Looking for new items...</div>');
                recentlyAddedConnected();
                % endif
            } else if (data.connected === false) {
                clearInterval(server_status);
                % if 'current_activity' in config['home_sections']:
                $('#currentActivity').html('<div id="dashboard-no-activity" class="text-muted">' + error_msg + '</div>');
                % endif
                % if 'recently_added' in config['home_sections']:
                $('#recentlyAdded').html('<div id="dashboard-no-recently-added" class="text-muted">' + error_msg + '</div>');
                % endif
            }
        });
    }, 1000);
    % endif
</script>
% if 'current_activity' in config['home_sections']:
<script>
    var defaultHandler = {
        get: function(target, name) {
            return target.hasOwnProperty(name) ? target[name] : 'Unknown';
        }
    };

    var create_instances = [];
    var activity_ready = true;

    $('#currentActivityHeader-bandwidth-tooltip').tooltip({ container: 'body', placement: 'right', delay: 50 });

    function getCurrentActivity() {
        activity_ready = false;

        $.ajax({
            url: 'get_activity',
            type: 'GET',
            cache: false,
            async: true,
            error: function (xhr, status, error) {
                console.log(status + ': ' + error);
                activity_ready = true;
            },
            complete: function (xhr, status) {
                $('#dashboard-checking-activity').remove();

                var current_activity;
                try {
                    current_activity = $.parseJSON(xhr.responseText);
                } catch (e) {
                    console.log(status + ': ' + e);
                    current_activity = null;
                }

                if (!(current_activity)) {
                    $('#currentActivityHeader').hide();
                    $('#currentActivity').html('<div id="dashboard-no-activity" class="text-muted">' + error_msg + '</div>');
                    return
                }

                var stream_count = parseInt(current_activity.stream_count);
                var sessions = current_activity.sessions;

                if (stream_count) {
                    $('#dashboard-no-activity').remove();

                    // Update the header stream counts
                    var sc_dp = current_activity.stream_count_direct_play,
                        sc_ds = current_activity.stream_count_direct_stream,
                        sc_tc = current_activity.stream_count_transcode,
                        total_bw = current_activity.total_bandwidth,
                        lan_bw = current_activity.lan_bandwidth,
                        wan_bw = current_activity.wan_bandwidth;
                    var streams_header = stream_count + ' stream' + (stream_count > 1 ? 's' : '') + ' (';
                    if (sc_dp) {
                        streams_header += sc_dp + ' direct play' + (sc_dp > 1 ? 's' : '') + ', ';
                    }
                    if (sc_ds) {
                        streams_header += sc_ds + ' direct stream' + (sc_ds > 1 ? 's' : '') + ', ';
                    }
                    if (sc_tc) {
                        streams_header += sc_tc + ' transcode' + (sc_tc > 1 ? 's' : '') + ', ';
                    }
                    streams_header = streams_header.replace(/, $/, '') + ')';
                    $('#currentActivityHeader-streams').text(streams_header);

                    var bandwidth_header = ((total_bw > 1000000) ? ((total_bw / 1000000).toFixed(1) + ' Gbps') : ((total_bw > 1000) ? ((total_bw / 1000).toFixed(1) + ' Mbps') : (total_bw + ' kbps')));
                    var lan_wan_bandwidth_header = '';
                    if (lan_bw) {
                        lan_wan_bandwidth_header += 'LAN: ' + ((lan_bw > 1000000) ? ((lan_bw / 1000000).toFixed(1) + ' Gbps') : ((lan_bw > 1000) ? ((lan_bw / 1000).toFixed(1) + ' Mbps') : (lan_bw + ' kbps'))) + ', ';
                    }
                    if (wan_bw) {
                        lan_wan_bandwidth_header += 'WAN: ' + ((wan_bw > 1000000) ? ((wan_bw / 1000000).toFixed(1) + ' Gbps') : ((wan_bw > 1000) ? ((wan_bw / 1000).toFixed(1) + ' Mbps') : (wan_bw + ' kbps'))) + ', ';
                    }
                    if (lan_wan_bandwidth_header) {
                        bandwidth_header += ' (' + lan_wan_bandwidth_header.replace(/, $/, '') + ')';
                    }
                    $('#currentActivityHeader-bandwidth').text(bandwidth_header);

                    $('#currentActivityHeader').show();

                    sessions.forEach(function (session) {
                        var s = (typeof Proxy === "function") ? new Proxy(session, defaultHandler) : session;
                        var key = s.session_key;
                        var session_id = s.session_id;
                        var instance = $('#activity-instance-' + key);

                        // Create a new instance if it doesn't exist or recreate the entire instance
                        // if the rating key changed (for movies or episodes) of guid changed (for live tv) with the same session key
                        if (!(instance.length) ||
                                (s.media_type !== 'track' && s.rating_key !== instance.data('rating_key').toString()) ||
                                (s.live === 1 && s.guid !== instance.data('guid'))) {
                            create_instances.push(key);
                            getActivityInstance(key);
                            return;
                        }

                        // Update play state icon
                        var state_icon = '';
                        switch (s.state) {
                            case 'playing':
                                state_icon = '<i class="fa fa-fw fa-play"></i>&nbsp;';
                                break;
                            case 'paused':
                                state_icon = '<i class="fa fa-fw fa-pause"></i>&nbsp;';
                                break;
                            case 'buffering':
                                state_icon = '<i class="fa fa-fw fa-spinner"></i>&nbsp;';
                                break;
                            case 'error':
                                state_icon = '<i class="fa fa-fw fa-exclamation-triangle"></i>&nbsp;';
                                break;
                            default:
                                state_icon = '<i class="fa fa-fw fa-question-circle"></i>&nbsp;';
                        }
                        $('#play-state-' + key).html(state_icon).attr('title', capitalizeFirstLetter(s.state));

                        // 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').toString()) {
                                $('#background-' + key).css('background-image', 'url(' + page('pms_image_proxy', s.art, s.rating_key, 500, 280, 40, '282828', 3, 'art', true) + ')');
                                $('#metadata-grandparent_title-' + key)
                                    .attr('href', page('info', s.grandparent_rating_key))
                                    .attr('title', s.original_title || s.grandparent_title)
                                    .text(s.original_title || s.grandparent_title);
                            }
                            // Update cover if album changed
                            if (s.parent_rating_key !== instance.data('parent_rating_key').toString()) {
                                $('#poster-' + key).css('background-image', 'url(' + page('pms_image_proxy', s.parent_thumb, s.parent_rating_key, 300, 300, null, null, null, 'poster', true) + ')');
                                $('#poster-' + key + '-bg').css('background-image', 'url(' + page('pms_image_proxy', s.parent_thumb, s.parent_rating_key, 300, 300, 60, '282828', 3, 'poster', true) + ')');
                                $('#poster-url-' + key)
                                    .attr('href', page('info', s.parent_rating_key))
                                    .attr('title', s.parent_title);
                                $('#metadata-parent_title-' + key)
                                    .attr('href', page('info', s.parent_rating_key))
                                    .attr('title', s.parent_title)
                                    .text(s.parent_title);
                            }
                            // Update cover if track changed
                            if (s.rating_key !== instance.data('rating_key').toString()) {
                                $('#metadata-grandparent_title-' + key)
                                    .attr('href', page('info', s.grandparent_rating_key))
                                    .attr('title', s.original_title || s.grandparent_title)
                                    .text(s.original_title || s.grandparent_title);
                                $('#metadata-title-' + key)
                                    .attr('href', page('info', s.rating_key))
                                    .attr('title', s.title)
                                    .text(s.title);
                            }
                        }

                        // Update the transcode state
                        var transcode_decision = '';
                        if (s.transcode_decision === 'transcode') {
                            var throttled = (s.transcode_throttled === 1) ? ' (Throttled)' : ' (Speed: ' + s.transcode_speed + ')';
                            transcode_decision = 'Transcode' + throttled;
                        } else if (s.transcode_decision === 'copy') {
                            transcode_decision = 'Direct Stream';
                        } else {
                            transcode_decision = 'Direct Play';
                        }
                        $('#transcode_decision-' + key).html(transcode_decision);

                        var transcode_container = '';
                        if (s.stream_container_decision === 'transcode') {
                            transcode_container = 'Converting (' + s.container.toUpperCase() + ' <i class="fa fa-long-arrow-right"></i> ' + s.stream_container.toUpperCase() + ')';
                        } else {
                            transcode_container = 'Direct Play (' + s.stream_container.toUpperCase() + ')';
                        }
                        $('#transcode_container-' + key).html(transcode_container);

                        var video_decision = '';
                        if (['movie', 'episode', 'clip'].indexOf(s.media_type) > -1 && s.stream_video_decision) {
                            var v_bd =  (s.video_dynamic_range !== 'SDR') ? ' ' + s.video_dynamic_range : '';
                            var sv_bd =  (s.stream_video_dynamic_range !== 'SDR' || v_bd) ? ' ' + s.stream_video_dynamic_range : '';
                            var v_res= '';
                            switch (s.video_resolution.toLowerCase()) {
                                case 'sd':
                                    v_res = 'SD';
                                    break;
                                case '4k':
                                    v_res = '4k';
                                    break;
                                default:
                                    v_res = s.video_full_resolution;
                            }
                            var sv_res = '';
                            switch (s.stream_video_resolution.toLowerCase()) {
                                case 'sd':
                                    sv_res = 'SD';
                                    break;
                                case '4k':
                                    sv_res = '4k';
                                    break;
                                default:
                                    sv_res = s.stream_video_full_resolution;
                            }
                            if (s.stream_video_decision === 'transcode') {
                                var hw_d = (s.transcode_hw_decoding === 1) ? ' (HW)' : '';
                                var hw_e = (s.transcode_hw_encoding === 1) ? ' (HW)' : '';
                                video_decision = 'Transcode (' + s.video_codec.toUpperCase() + hw_d + ' ' + v_res + v_bd + ' <i class="fa fa-long-arrow-right"></i> ' + s.stream_video_codec.toUpperCase() + hw_e + ' ' + sv_res + sv_bd + ')';
                            } else if (s.stream_video_decision === 'copy') {
                                video_decision = 'Direct Stream (' + s.stream_video_codec.toUpperCase() + ' ' + sv_res + sv_bd + ')';
                            } else {
                                video_decision = 'Direct Play (' + s.stream_video_codec.toUpperCase() + ' ' + sv_res + sv_bd + ')';
                            }
                        } else if (s.media_type === 'photo') {
                            video_decision = 'Direct Play (' + s.width + 'x' + s.height + ')';
                        }
                        $('#video_decision-' + key).html(video_decision);

                        var audio_decision = '';
                        if (['movie', 'episode', 'clip', 'track'].indexOf(s.media_type) > -1 && s.stream_audio_decision) {
                            var audio_language = (s.media_type !== 'track') ? (s.audio_language || 'Unknown') + ' - ' : '';
                            var a_codec = (s.audio_codec === 'truehd') ? 'TrueHD' : s.audio_codec.toUpperCase();
                            var sa_codec = (s.stream_audio_codec === 'truehd') ? 'TrueHD' : s.stream_audio_codec.toUpperCase();
                            if (s.stream_audio_decision === 'transcode') {
                                audio_decision = 'Transcode (' + audio_language + a_codec + ' ' + capitalizeFirstLetter(s.audio_channel_layout.split('(')[0]) + ' <i class="fa fa-long-arrow-right"></i> ' + sa_codec + ' ' + capitalizeFirstLetter(s.stream_audio_channel_layout.split('(')[0]) + ')';
                            } else if (s.stream_audio_decision === 'copy') {
                                audio_decision = 'Direct Stream (' + audio_language + sa_codec + ' ' + capitalizeFirstLetter(s.stream_audio_channel_layout.split('(')[0]) + ')';
                            } else {
                                audio_decision = 'Direct Play (' + audio_language + sa_codec + ' ' + capitalizeFirstLetter(s.stream_audio_channel_layout.split('(')[0]) + ')';
                            }
                        }
                        $('#audio_decision-' + key).html(audio_decision);

                        var subtitle_decision = 'None';
                        if (['movie', 'episode', 'clip'].indexOf(s.media_type) > -1 && s.subtitles === 1) {
                            var subtitle_codec = (s.stream_subtitle_codec && s.stream_subtitle_transient) ? 'None' : s.subtitle_codec.toUpperCase();
                            if (s.stream_subtitle_decision === 'transcode') {
                                subtitle_decision = 'Transcode ('+ (s.subtitle_language || 'Unknown')+ ' - ' + subtitle_codec + ' <i class="fa fa-long-arrow-right"></i> ' + s.stream_subtitle_codec.toUpperCase() + ')';
                            } else if (s.stream_subtitle_decision === 'copy') {
                                subtitle_decision = 'Direct Stream ('+ (s.subtitle_language || 'Unknown')+ ' - ' + subtitle_codec + ')';
                            } else if (s.stream_subtitle_decision === 'burn') {
                                subtitle_decision = 'Burn ('+ (s.subtitle_language || 'Unknown')+ ' - ' + subtitle_codec + ')';
                            } else {
                                subtitle_decision = 'Direct Play ('+ (s.subtitle_language || 'Unknown')+ ' - ' + ((s.synced_version === '1') ? subtitle_codec : s.stream_subtitle_codec.toUpperCase()) + ')';
                            }
                        }
                        $('#subtitle_decision-' + key).html(subtitle_decision);

                        // Update the stream quality profile and bandwidth
                        if (s.media_type !== 'photo' && s.quality_profile !== 'Unknown') {
                            var br = parseInt(s.stream_bitrate) || '';
                            if (br) {
                                if (br > 1000) {
                                    br = ' (' + (br / 1000).toFixed(1) + ' Mbps)';
                                } else {
                                    br = ' (' + br + ' kbps)';
                                }
                            }
                            $('#stream_quality-' + key).html(s.quality_profile + br);
                        } else {
                            $('#stream_quality-' + key).html(s.quality_profile);
                        }
                        $('#optimized_version-' + key).html(s.optimized_version_profile + ' (' + s.optimized_version_title + ')');
                        $('#synced_quality_profile-' + key).html(s.synced_quality_profile);

                        $('#location-' + key).html(s.location.toUpperCase());

                        if (s.media_type !== 'photo' && s.bandwidth !== 'Unknown') {
                            var bw = parseInt(s.bandwidth) || 0;
                            if (bw > 1000000) {
                                bw = (bw / 1000000).toFixed(1) + ' Gbps';
                            } else if (bw > 1000) {
                                bw = (bw / 1000).toFixed(1) + ' Mbps';
                            } else {
                                bw = bw + ' kbps'
                            }
                            $('#stream-bandwidth-' + key).html(bw);
                        }

                        // Update the stream progress times
                        $('#stream-eta-' + key).html(moment().add(parseInt(s.duration) - parseInt(s.view_offset), 'milliseconds').format(time_format));
                        $('#stream-duration-' + key).html(millisecondsToMinutes(parseInt(s.stream_duration), false));
                        var stream_view_offset = $('#stream-view-offset-' + key);
                        stream_view_offset.data('state', s.state);
                        if (stream_view_offset.data('last_view_offset') !== s.view_offset) {
                            stream_view_offset.data('last_view_offset', s.view_offset).data('view_offset', s.view_offset);
                        }

                        // Update the progress bars
                        var duration = parseInt(s.duration);
                        var transcode_progress = duration ? Math.round(s.transcode_max_offset_available * 1000 / duration * 100) : s.transcode_progress;
                        $('#buffer-bar-' + key).css({width: parseInt(transcode_progress) + '%'}).html(transcode_progress + '%')
                            .attr('data-original-title', 'Transcoder Progress ' + transcode_progress + '%');
                        if (s.live !== 1) {
                            var progress_bar = $('#progress-bar-' + key);
                            progress_bar.data('state', s.state);
                            if (progress_bar.data('last_view_offset') !== s.view_offset) {
                                progress_bar.data('last_view_offset', s.view_offset).data('view_offset', s.view_offset);
                            }
                        }

                        // Add temporary class so we know which instances are still active
                        instance.addClass('updated-temp');
                    });

                    // Remove finished instances
                    $('div[id^=activity-instance-]').each(function (i, instance) {
                        if ($(instance).hasClass('updated-temp')) {
                            $(instance).removeClass('updated-temp');
                        } else {
                            $(instance).find('[data-toggle=tooltip]').tooltip('destroy');
                            $(instance).find('[data-toggle=popover]').popover('destroy');
                            $(instance).remove();
                        }
                    });

                } else {
                    $('#currentActivityHeader').hide();
                    $('#currentActivity').html('<div id="dashboard-no-activity" class="text-muted">Nothing is currently being played.</div>');
                }

                activity_ready = true;
            }
        });
    }

    function getActivityInstance(session_key) {
        $.ajax({
            url: 'get_current_activity_instance',
            type: 'GET',
            cache: false,
            async: true,
            data: {
                session_key: session_key
            },
            complete: function(xhr, status) {
                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 });
                $('#activity-instance-' + session_key + ' [data-toggle=popover]').popover({
                    html: true,
                    sanitize: false,
                    container: 'body',
                    trigger: 'hover',
                    placement: 'right',
                    delay: 50,
                    template: '<div class="popover channel-thumbnail-popover" role="tooltip"><div class="arrow" style="top: 50%;"></div><div class="popover-content"></div></div>',
                    content: function () {
                        return '<div class="channel-thumbnail" style="background-image: url(' + $(this).data('img') + ');" />';
                    }
                });
                $('#terminate-button-' + session_key).tooltip('destroy').tooltip({ container: 'body', placement: 'left', delay: 50 });
                lockScroll('#activity-instance-' + session_key + ' .dashboard-activity-info-scroller');

                var index = create_instances.indexOf(session_key);
                if (index > -1) {
                    create_instances.splice(index, 1);
                }
            }
        });
    }

    function activityConnected() {
        getCurrentActivity();
        setInterval(function () {
            if (!(create_instances.length) && activity_ready) {
                getCurrentActivity();
            }
        }, ${config['home_refresh_interval'] * 1000});

        setInterval(function(){
            $('.progress_time_offset').each(function () {
                if ($(this).data('state') === 'playing' && $(this).data('view_offset') >= 0) {
                    var view_offset = parseInt($(this).data('view_offset'));
                    var stream_duration = parseInt($(this).data('stream_duration'));
                    var timestamp = millisecondsToMinutes(Math.min(view_offset, stream_duration), false);
                    $(this).html(timestamp).data('view_offset', Math.min(view_offset + 1000, stream_duration))
                }
            });
            $('.progress-bar').each(function () {
                if ($(this).data('state') === 'playing' && $(this).data('view_offset') >= 0) {
                    var view_offset = parseInt($(this).data('view_offset'));
                    var stream_duration = parseInt($(this).data('stream_duration'));
                    var progress_percent = Math.floor(view_offset / stream_duration * 100);
                    progress_percent = (progress_percent >= 0) ? Math.min(progress_percent, 100) : 100;
                    $(this).css({width: progress_percent + '%'}).html(progress_percent + '%')
                        .attr('data-original-title', 'Stream Progress ' + progress_percent + '%')
                        .data('view_offset', Math.min(view_offset + 1000, stream_duration));
                }
            });
        }, 1000);
    }

    $('#currentActivity').on('click', '.external_ip-modal', function () {
        $.get('get_ip_address_details', {
            ip_address: $(this).data('ip'),
            location: $(this).data('location'),
            secure: $(this).data('secure'),
            relayed: $(this).data('relayed')
        }).then(function (jqXHR) {
            $("#ip-info-modal").html(jqXHR);
        });
    });

    $('#currentActivity').on('click', '.raw-stream-info-modal', function () {
        $.ajax({
            url: 'get_activity',
            type: 'GET',
            cache: false,
            async: true,
            data: {
                session_key: $(this).data('key')
            },
            error: function (xhr, status, error) {
                console.log(status + ': ' + error);
            },
            complete: function (xhr, status) {
                var session = $.parseJSON(xhr.responseText);
                $('#raw-stream-info-title').text(session.full_title);
                $('#raw-stream-info-user').text(session.friendly_name);
                $('#raw-stream-info').text(JSON.stringify(session, Object.keys(session).sort(), 4));
            }
        });
    });

    % if _session['user_group'] == 'admin':
    // Terminate session
    $('#currentActivity').on('click', '.dashboard-activity-terminate-session', function (e) {
        e.preventDefault();
        var session_id = $(this).data('id');
        var key = $(this).data('key');
        var instance = $('#activity-instance-' + key);

        $('#terminate-user').text(instance.find('.dashboard-activity-metadata-user').text());
        $('#terminate-title').text(instance.find('.dashboard-activity-metadata-title').text());
        $('#terminate-subtitle').text(instance.find('.dashboard-activity-metadata-subtitle').text());

        $('#terminate-session-modal').modal();
        $('#terminate-session-modal').one('click', '#confirm-terminate-session', function () {
            var message = $('#terminate-message').val();

            showMsg('Terminating session', true);

            $.ajax({
                url: 'terminate_session',
                data: {
                    session_key: key,
                    session_id: session_id,
                    message: message
                },
                async: true,
                success: function (data) {
                    if (data.result === 'success') {
                        setTimeout(function() {
                            getCurrentActivity();
                            showMsg('<i class="fa fa-check"></i> ' + data.message, false, true, 5000);
                        }, 2500);
                    } else {
                        showMsg('<i class="fa fa-exclamation-circle"></i> ' + data.message, false, true, 5000, true);
                    }
                }
            });
        });
    });

    $('#sessions-xml').on('tripleclick', function () {
        openPlexXML('/status/sessions');
    });
    % endif
</script>
% endif
% if 'watch_stats' in config['home_sections'] or 'library_stats' in config['home_sections']:
<script>
    function statsCardCallback() {
        $('.dashboard-stats-instance .dashboard-stats-info-scroller').scrollbar();
        loadAllBlurHash();

        function changeImages(elem) {
            var stat_id = $(elem).data('stat_id');
            var art = $(elem).data('art');
            var thumb = $(elem).data('thumb');
            var user_id = $(elem).data('user_id');
            var library_type = $(elem).data('library-type');
            var user_thumb = $(elem).data('user_thumb');
            var rating_key = $(elem).data('rating_key');
            var grandparent_rating_key = $(elem).data('grandparent_rating_key');
            var guid = $(elem).data('guid');
            var live = $(elem).data('live');
            var library_art = $(elem).data('library_art');
            var library_thumb = $(elem).data('library_thumb');
            var [height, fallback_poster, fallback_art] = [450, 'poster', 'art'];
            if ($.inArray(stat_id, ['top_music', 'popular_music']) > -1) {
                [height, fallback_poster, fallback_art] = [300, 'cover', 'art'];
            } else if (live) {
                [height, fallback_poster, fallback_art] = [450, 'poster-live', 'art-live'];
            }
            var href = '#';

            if (stat_id === 'most_concurrent') {
                return
            } else if (stat_id === 'top_libraries') {
                $('#stats-background-' + stat_id).css('background-image', 'url(' + page('pms_image_proxy', art || library_art, null, 500, 280, 40, '282828', 3, fallback_art) + ')');
                $('#stats-thumb-' + stat_id).removeClass(function (index, className) {
                    return (className.match (/(^|\s)svg-icon library-\S+/g) || []).join(' ')});
                if (library_thumb.startsWith('http')) {
                    $('#stats-thumb-' + stat_id).css('background-image', 'url(' + page('pms_image_proxy', library_thumb, null, 100, 100, null, null, null, 'cover') + ')');
                } else {
                    $('#stats-thumb-' + stat_id).css('background-image', '')
                        .addClass('svg-icon library-' + library_type);
                }
            } else if (stat_id === 'top_users') {
                loadBlurHash($('#stats-background-' + stat_id), page('pms_image_proxy', user_thumb || 'interfaces/default/images/gravatar-default.png', null, 100, 100, 40, '282828', 0, 'user'));
                $('#stats-thumb-' + stat_id).css('background-image', 'url(' + page('pms_image_proxy', user_thumb || 'interfaces/default/images/gravatar-default.png', null, 100, 100, null, null, null, 'user') + ')');
                if (user_id) {
                    href = page('user', user_id);
                }
                $('#stats-thumb-url-' + stat_id).attr('href', href).prop('title', $(elem).data('user'));
            } else if (stat_id === 'top_platforms') {
                $('#stats-thumb-' + stat_id).removeClass(function (index, className) {
                    return (className.match (/(^|\s)platform-\S+/g) || []).join(' ');
                }).addClass('platform-' + $(elem).data('platform'));
                $('#stats-background-' + stat_id).removeClass(function (index, className) {
                    return (className.match (/(^|\s)platform-\S+/g) || []).join(' ');
                }).addClass('platform-' + $(elem).data('platform') + '-rgba');
            } else {
                if (rating_key) {
                    if (live) {
                        href = page('info', rating_key, guid, true, live);
                    } else {
                        href = page('info', rating_key);
                    }
                }
                var img_rating_key = grandparent_rating_key || rating_key;
                $('#stats-thumb-url-' + stat_id).attr('href', href).prop('title', $(elem).data('title'));
                $('#stats-background-' + stat_id).css('background-image', 'url(' + page('pms_image_proxy', art, img_rating_key, 500, 280, 40, '282828', 3, fallback_art) + ')');
                $('#stats-thumb-' + stat_id).css('background-image', 'url(' + page('pms_image_proxy', thumb, img_rating_key, 300, height, null, null, null, fallback_poster) + ')');
                $('#stats-thumb-' + stat_id + '-bg').css('background-image', 'url(' + page('pms_image_proxy', thumb, img_rating_key, 300, height, 60, '282828', 3, fallback_poster) + ')');
                $('#library-stats-background-' + stat_id).css('background-image', 'url(' + page('pms_image_proxy', art || library_art, img_rating_key, 500, 280, 40, '282828', 3, library_art || fallback_art) + ')');
                if (thumb.startsWith('http')) {
                    $('#library-stats-thumb-' + stat_id).css('background-image', 'url(' + page('pms_image_proxy', thumb, img_rating_key, 300, 300, null, null, null, 'cover') + ')')
                        .removeClass('svg-icon library-' + stat_id);
                } else {
                    $('#library-stats-thumb-' + stat_id).css('background-image', '')
                        .addClass('svg-icon library-' + stat_id);
                }
            }
        }

        $('.dashboard-stats-info-item').mouseenter(function () {
            changeImages(this);
            if ($(this).data('stat_id') === 'last_watched') {
                var friendly_name = $(this).data('friendly_name');
                var last_watch = moment($(this).data('last_watch'), 'X').format(date_format);
                $('#last-watched-header-info').html(friendly_name);
            } else if ($(this).data('stat_id') === 'most_concurrent') {
                var started = moment($(this).data('started'), 'X').format(date_format + ' ' + time_format);
                $('#most-concurrent-header-info').html(started);
            }
        });
        $('.dashboard-stats-instance').mouseleave(function () {
            changeImages($(this).find('.dashboard-stats-info-item').first());
            if ($(this).data('stat_id') === 'last_watched') {
                $('#last-watched-header-info').text($(this).find('.dashboard-stats-info-item').first().data('friendly_name'));
            } else if ($(this).data('stat_id') === 'most_concurrent') {
                $('#most-concurrent-header-info').text('streams');
            }
        });
    }
</script>
% endif
% if 'watch_stats' in config['home_sections']:
<script>
    function getHomeStats(time_range, stats_type) {
        showMsg("Loading watch statistics...", true, false, 0);

        $.ajax({
            url: 'home_stats',
            type: 'GET',
            cache: false,
            async: true,
            data: {
                time_range: time_range,
                stats_type: stats_type
            },
            complete: function (xhr, status) {
                $("#home-stats").html(xhr.responseText);
                $('#ajaxMsg').fadeOut();
                lockScroll('#home-stats .dashboard-stats-info-scroller');
                statsCardCallback();
            }
        });
    }

    var stats_type = getLocalStorage('home_stats_type', 'plays');
    var time_range = getLocalStorage('home_stats_days', 30);

    $('#watched-stats-' + stats_type).prop('checked', true);
    $('#watched-stats-' + stats_type).closest('label').addClass('active');
    $('#watched-stats-days').val(time_range);

    getHomeStats(time_range, stats_type);

    $('input[name=watched-stats-type]').change(function () {
        stats_type = $(this).filter(':checked').val();
        setLocalStorage('home_stats_type', stats_type);
        getHomeStats(time_range, stats_type);
    });
    $('#watched-stats-days').change(function () {
        forceMinMax($(this));
        time_range = $(this).val();
        setLocalStorage('home_stats_days', time_range);
        getHomeStats(time_range, stats_type);
    });

    $('#watched-stats-days').tooltip({ container: 'body', placement: 'top', html: true });
</script>
% endif
% if 'library_stats' in config['home_sections']:
<script>
    function getLibraryStats() {
        $.ajax({
            url: 'library_stats',
            type: 'GET',
            cache: false,
            async: true,
            data: { },
            complete: function (xhr, status) {
                $("#library-stats").html(xhr.responseText);
                statsCardCallback();
            }
        });
    }
    getLibraryStats();
</script>
% endif
% if 'recently_added' in config['home_sections']:
<script>
    function recentlyAdded(recently_added_count, recently_added_type) {
        showMsg("Loading recently added items...", true, false, 0);

        $.ajax({
            url: 'get_recently_added',
            type: 'GET',
            async: true,
            data: {
                count: recently_added_count,
                media_type: recently_added_type
            },
            beforeSend: function () {
                $(".dashboard-recent-media-row").animate({ scrollLeft: 0 }, 1000);
            },
            complete: function (xhr, status) {
                $("#recentlyAdded").html(xhr.responseText);
                $('#ajaxMsg').fadeOut();
                highlightScrollerButton("#recently-added");
                paginateScroller("#recently-added", ".paginate-added");
            }
        });
    }

    var recently_added_count = getLocalStorage('home_stats_recently_added_count', 50);
    var recently_added_type = getLocalStorage('home_stats_recently_added_type', 'all');;

    $('#recently-added-toggle-' + recently_added_type).prop('checked', true);
    $('#recently-added-toggle-' + recently_added_type).closest('label').addClass('active');
    $('#recently-added-count').val(recently_added_count);

    function recentlyAddedConnected() {
        recentlyAdded(recently_added_count, recently_added_type);
    }

    $('#recently-added-toggles').on('change', function () {
        $('#recently-added-toggles > label').removeClass('active');
        selected_filter = $('input[name=recently-added-toggle]:checked', '#recently-added-toggles');
        $(selected_filter).closest('label').addClass('active');
        recently_added_type = $(selected_filter).val();
        setLocalStorage('home_stats_recently_added_type', recently_added_type);
        recentlyAdded(recently_added_count, recently_added_type);
    });

    $('#recently-added-count').change(function () {
        forceMinMax($(this));
        recently_added_count = $(this).val();
        setLocalStorage('home_stats_recently_added_count', recently_added_count);
        recentlyAdded(recently_added_count, recently_added_type);
    });

    $('#recently-added-count').tooltip({ container: 'body', placement: 'top', html: true });

    $('#recently-added-xml').on('tripleclick', function () {
        openPlexXML('/library/recentlyAdded', false, {'X-Plex-Container-Start': 0, 'X-Plex-Container-Size': recently_added_count});
    });
</script>
% endif
% if _session['user_group'] == 'admin' and config['update_show_changelog']:
<script>
    $.ajax({
        url: 'get_changelog',
        data: {
            since_prev_release: true,
            update_shown: true
        },
        cache: false,
        async: true,
        complete: function (xhr, status) {
            $("#changelog-modal .modal-body").html(xhr.responseText);
            $('#changelog-modal').modal({
                backdrop: 'static',
                keyboard: false
            });
        }
    });
</script>
% endif
</%def>