Added history statistics

pull/1038/head
Louis Vézina 4 years ago
parent aac4b56349
commit 1cfc193758

@ -4,6 +4,7 @@ import os
import ast
from datetime import timedelta
import datetime
from dateutil import rrule
import pretty
import time
from operator import itemgetter
@ -1256,6 +1257,58 @@ class HistoryMovies(Resource):
return jsonify(draw=draw, recordsTotal=row_count, recordsFiltered=row_count, data=data)
class HistoryStats(Resource):
@authenticate
def get(self):
timeframe = request.args.get('timeframe') or 'month'
action = request.args.get('action') or 'All'
provider = request.args.get('provider') or 'All'
language = request.args.get('language') or 'All'
history_where_clause = " WHERE id"
# timeframe must be in ['week', 'month', 'trimester', 'year']
if timeframe == 'year':
days = 364
elif timeframe == 'trimester':
days = 90
elif timeframe == 'month':
days = 30
elif timeframe == 'week':
days = 6
history_where_clause += " AND datetime(timestamp, 'unixepoch') BETWEEN datetime('now', '-" + str(days) + \
" days') AND datetime('now', 'localtime')"
if action != 'All':
history_where_clause += " AND action = " + action
else:
history_where_clause += " AND action IN (1,2,3)"
if provider != 'All':
history_where_clause += " AND provider = '" + provider + "'"
if language != 'All':
history_where_clause += " AND language = '" + language + "'"
data_series = database.execute("SELECT strftime ('%Y-%m-%d',datetime(timestamp, 'unixepoch')) as date, "
"COUNT(id) as count FROM table_history" + history_where_clause +
" GROUP BY strftime ('%Y-%m-%d',datetime(timestamp, 'unixepoch'))")
data_movies = database.execute("SELECT strftime ('%Y-%m-%d',datetime(timestamp, 'unixepoch')) as date, "
"COUNT(id) as count FROM table_history_movie" + history_where_clause +
" GROUP BY strftime ('%Y-%m-%d',datetime(timestamp, 'unixepoch'))")
for dt in rrule.rrule(rrule.DAILY,
dtstart=datetime.datetime.now() - datetime.timedelta(days=days),
until=datetime.datetime.now()):
if not any(d['date'] == dt.strftime('%Y-%m-%d') for d in data_series):
data_series.append({'date': dt.strftime('%Y-%m-%d'), 'count': 0})
if not any(d['date'] == dt.strftime('%Y-%m-%d') for d in data_movies):
data_movies.append({'date': dt.strftime('%Y-%m-%d'), 'count': 0})
sorted_data_series = sorted(data_series, key=lambda i: i['date'])
sorted_data_movies = sorted(data_movies, key=lambda i: i['date'])
return jsonify(data_series=sorted_data_series, data_movies=sorted_data_movies)
class WantedSeries(Resource):
@authenticate
def get(self):
@ -1429,6 +1482,7 @@ api.add_resource(MovieTools, '/movie_tools')
api.add_resource(HistorySeries, '/history_series')
api.add_resource(HistoryMovies, '/history_movies')
api.add_resource(HistoryStats, '/history_stats')
api.add_resource(WantedSeries, '/wanted_series')
api.add_resource(WantedMovies, '/wanted_movies')

@ -25,7 +25,8 @@ from database import database, dict_mapper
from notifier import update_notifier
from urllib.parse import unquote
from get_languages import load_language_in_db, language_from_alpha3, language_from_alpha2, alpha2_from_alpha3
from get_languages import load_language_in_db, language_from_alpha3, language_from_alpha2, alpha2_from_alpha3, \
alpha3_from_alpha2
from flask import make_response, request, redirect, abort, render_template, Response, session, flash, url_for, \
send_file, stream_with_context
@ -247,6 +248,32 @@ def historymovies():
return render_template('historymovies.html')
@app.route('/history/stats/')
@login_required
def historystats():
data_providers = database.execute("SELECT DISTINCT provider FROM table_history WHERE provider IS NOT null "
"UNION SELECT DISTINCT provider FROM table_history_movie WHERE provider "
"IS NOT null")
data_providers_list = []
for item in data_providers:
data_providers_list.append(item['provider'])
data_languages = database.execute("SELECT DISTINCT language FROM table_history WHERE language IS NOT null "
"AND language != '' UNION SELECT DISTINCT language FROM table_history_movie "
"WHERE language IS NOT null AND language != ''")
data_languages_list = []
for item in data_languages:
splitted_lang = item['language'].split(':')
item = {"name": language_from_alpha2(splitted_lang[0]),
"code2": splitted_lang[0],
"code3": alpha3_from_alpha2(splitted_lang[0]),
"forced": True if len(splitted_lang) > 1 else False}
data_languages_list.append(item)
return render_template('historystats.html', data_providers=data_providers_list,
data_languages=sorted(data_languages_list, key=lambda i: i['name']))
@app.route('/wanted/series/')
@login_required
def wantedseries():

@ -0,0 +1 @@
@keyframes chartjs-render-animation{from{opacity:.99}to{opacity:1}}.chartjs-render-monitor{animation:chartjs-render-animation 1ms}.chartjs-size-monitor,.chartjs-size-monitor-expand,.chartjs-size-monitor-shrink{position:absolute;direction:ltr;left:0;top:0;right:0;bottom:0;overflow:hidden;pointer-events:none;visibility:hidden;z-index:-1}.chartjs-size-monitor-expand>div{position:absolute;width:1000000px;height:1000000px;left:0;top:0}.chartjs-size-monitor-shrink>div{position:absolute;width:200%;height:200%;left:0;top:0}

File diff suppressed because one or more lines are too long

@ -40,6 +40,7 @@
<link rel="stylesheet" href="{{ url_for('static',filename='css/bootstrap-select.css') }}"/>
<link rel="stylesheet" href="{{ url_for('static',filename='css/bootstrap-slider.min.css') }}"/>
<link rel="stylesheet" href="{{ url_for('static',filename='css/jquery.typeahead.min.css') }}"/>
<link rel="stylesheet" href="{{ url_for('static',filename='css/Chart.min.css') }}"/>
{% endblock head_css %}
@ -206,6 +207,7 @@
{% if settings.general.getboolean('use_radarr') %}
<li><a href="{{ url_for('historymovies') }}"> Movies</a></li>
{% endif %}
<li><a href="{{ url_for('historystats') }}"> Statistics</a></li>
</ul>
</li>
@ -325,6 +327,7 @@
<script src="{{ url_for('static',filename='js/bootstrap-slider.min.js') }}"></script>
<script src="{{ url_for('static',filename='moment/moment.js') }}"></script>
<script src="{{ url_for('static',filename='js/jquery.typeahead.min.js') }}"></script>
<script src="{{ url_for('static',filename='js/Chart.min.js') }}"></script>
<script>
{% if not request.endpoint == 'login_page' %}

@ -0,0 +1,149 @@
{% extends '_main.html' %}
{% block title %}History (Statistics) - Bazarr{% endblock %}
{% block bcleft %}
{% endblock bcleft %}
{% block bcright %}
{% endblock bcright %}
{% block body %}
<canvas id="history_stats" height="125"></canvas>
<nav id="edit_bar" class="navbar fixed-bottom navbar-dark bg-dark">
<div class="form-check form-check-inline">
<div class="form-group" style="margin-bottom: 0px;">
<label for="timeframe_select">Time frame: </label>
<select class="selectpicker show-tick" id="timeframe_select" name="timeframe">
<option value="week">Last week</option>
<option value="month" selected>Last month</option>
<option value="trimester">Last trimester</option>
<option value="year">Last year</option>
</select>
</div>
</div>
<div class="form-check form-check-inline">
<div class="form-group" style="margin-bottom: 0px;">
<label for="action_select">Action: </label>
<select class="selectpicker show-tick" id="action_select" name="action">
<option value="All" selected>All</option>
<option value="1">Automatically Downloaded</option>
<option value="2">Manually Downloaded</option>
<option value="3">Upgraded</option>
</select>
</div>
</div>
<div class="form-check form-check-inline">
<div class="form-group" style="margin-bottom: 0px;">
<label for="provider_select">Provider: </label>
<select class="selectpicker show-tick" id="provider_select" name="provider"></select>
</div>
</div>
<div class="form-check form-check-inline">
<div class="form-group" style="margin-bottom: 0px;">
<label for="language_select">Language: </label>
<select class="selectpicker" id="language_select" name="language"></select>
</div>
</div>
</nav>
{% endblock body %}
{% block tail %}
<script>
$(document).ready(function () {
getEnabledLanguages();
getEnabledProviders();
var timeframe = 'month';
var action = 'All';
var provider = 'All';
var language = 'All';
var labels_series = [];
var data_series = [];
var labels_movies = [];
var data_movies = [];
var history_chart = new Chart($('#history_stats'), {
type: 'bar',
data: {
labels: labels_series,
datasets: [{
label: 'Series',
backgroundColor: '#2193b5',
data: data_series
}, {
label: 'Movies',
backgroundColor: '#ffc230',
data: data_movies
}]
},
options: {
responsive: true,
scales: {
yAxes: [{
ticks: {
precision: 0
}
}]
}
}
});
get_data();
$('.selectpicker').on('change', function() {
timeframe = $('#timeframe_select').selectpicker('val');
action = $('#action_select').selectpicker('val');
provider = $('#provider_select').selectpicker('val');
language = $('#language_select').selectpicker('val');
get_data();
})
function get_data() {
$.ajax({
dataType: "json",
url: "{{ url_for('api.historystats') }}?timeframe=" + timeframe + "&action=" + action + "&provider=" + provider + "&language=" + language,
success: function(json_data) {
labels_series = json_data.data_series.map(function(e) {
return e.date;
});
data_series = json_data.data_series.map(function(e) {
return e.count;
});
data_movies = json_data.data_movies.map(function(e) {
return e.count;
});
history_chart.data.labels = labels_series;
history_chart.data.datasets[0].data = data_series;
history_chart.data.datasets[1].data = data_movies;
history_chart.update();
}
});
}
});
function getEnabledLanguages() {
$('#language_select').append('<option value="All" selected>All</option>');
{% for item in data_languages %}
$('#language_select').append('<option value="{{item['code2'] + (':forced' if item['forced'] else '')}}">{{item['name'] + (' Forced' if item['forced'] else '')}}</option>');
{% endfor %}
$("#language_select").selectpicker("refresh");
}
function getEnabledProviders() {
$('#provider_select').append('<option value="All" selected>All</option>');
{% for item in data_providers %}
$('#provider_select').append('<option value="{{item}}">{{item}}</option>');
{% endfor %}
$("#provider_select").selectpicker("refresh");
}
</script>
{% endblock tail %}
Loading…
Cancel
Save