diff --git a/tubearchivist/api/src/aggs.py b/tubearchivist/api/src/aggs.py
index f663d134..b8db502b 100644
--- a/tubearchivist/api/src/aggs.py
+++ b/tubearchivist/api/src/aggs.py
@@ -211,11 +211,8 @@ class BiggestChannel(AggBase):
}
order_choices = ["doc_count", "duration", "media_size"]
- def process(self, order_by=False):
- """process aggregation"""
-
- if order_by and order_by in self.order_choices:
- self.data["aggs"][self.name]["multi_terms"]["order"] = order_by
+ def process(self):
+ """process aggregation, order_by validated in the view"""
aggregations = self.get()
buckets = aggregations[self.name]["buckets"]
@@ -226,6 +223,9 @@ class BiggestChannel(AggBase):
"name": i["key"][0].title(),
"doc_count": i["doc_count"]["value"],
"duration": i["duration"]["value"],
+ "duration_str": DurationConverter().get_str(
+ i["duration"]["value"]
+ ),
"media_size": i["media_size"]["value"],
}
for i in buckets
diff --git a/tubearchivist/api/views.py b/tubearchivist/api/views.py
index cf9521f4..24db6dda 100644
--- a/tubearchivist/api/views.py
+++ b/tubearchivist/api/views.py
@@ -1025,7 +1025,7 @@ class StatBiggestChannel(ApiBaseView):
def get(self, request):
"""handle get request"""
- order = request.GET.get("order")
+ order = request.GET.get("order", False)
if order and order not in self.order_choices:
message = {"message": f"invalid order parameter {order}"}
return Response(message, status=400)
diff --git a/tubearchivist/home/templates/home/settings.html b/tubearchivist/home/templates/home/settings.html
index 8a2256e8..edaaeaf0 100644
--- a/tubearchivist/home/templates/home/settings.html
+++ b/tubearchivist/home/templates/home/settings.html
@@ -12,5 +12,21 @@
Watch Progress
+
+
Biggest Channels
+
+
+
+
+ Name |
+ Videos |
+ Duration |
+ Media Size |
+
+
+
+
+
+
{% endblock settings_content %}
diff --git a/tubearchivist/static/css/style.css b/tubearchivist/static/css/style.css
index df9dfadd..a70cba4a 100644
--- a/tubearchivist/static/css/style.css
+++ b/tubearchivist/static/css/style.css
@@ -82,6 +82,7 @@ ul {
td, th, span, label {
font-family: Sen-Regular, sans-serif;
color: var(--main-font);
+ text-align: left;
}
select, input {
@@ -655,6 +656,10 @@ video:-webkit-full-screen {
grid-template-columns: 1fr 1fr;
}
+.info-box-1 {
+ grid-template-columns: 1fr;
+}
+
.info-box img {
width: 80px;
margin: 0 15px;
diff --git a/tubearchivist/static/stats.js b/tubearchivist/static/stats.js
index 0bc5e402..0bdba344 100644
--- a/tubearchivist/static/stats.js
+++ b/tubearchivist/static/stats.js
@@ -96,9 +96,37 @@ function buildWatchTile(title, watchDetail) {
return tile;
}
+function biggestChannel() {
+ let apiEndpoint = '/api/stats/biggestchannels/';
+ let responseData = apiRequest(apiEndpoint, 'GET');
+ let tBody = document.getElementById('biggestChannelTable');
+ for (let i = 0; i < responseData.length; i++) {
+ const channelData = responseData[i];
+ let tableRow = buildChannelRow(channelData);
+ tBody.appendChild(tableRow);
+ }
+}
+
+function buildChannelRow(channelData) {
+ let tableRow = document.createElement('tr');
+ tableRow.innerHTML = `
+ ${channelData.name} |
+ ${channelData.doc_count} |
+ ${channelData.duration_str} |
+ ${humanFileSize(channelData.media_size)} |
+ `;
+ return tableRow;
+}
+
+function humanFileSize(size) {
+ let i = size === 0 ? 0 : Math.floor(Math.log(size) / Math.log(1024));
+ return (size / Math.pow(1024, i)).toFixed(1) * 1 + ' ' + ['B', 'kB', 'MB', 'GB', 'TB'][i];
+}
+
function buildStats() {
primaryStats();
watchStats();
+ biggestChannel();
}
buildStats();