Combine view and download graphs

This commit is contained in:
2021-12-16 21:20:05 +01:00
parent c5c8d6f8d5
commit 81c8baf639
4 changed files with 223 additions and 116 deletions

View File

@@ -39,11 +39,12 @@ const loadGraph = (minutes, interval, live) => {
dateStr += ":" + ("00" + date.getMinutes()).slice(-2); dateStr += ":" + ("00" + date.getMinutes()).slice(-2);
resp.views.timestamps[idx] = " " + dateStr + " "; // Poor man's padding resp.views.timestamps[idx] = " " + dateStr + " "; // Poor man's padding
}); });
graphViews.chart().data.labels = resp.views.timestamps; graphViews.data().labels = resp.views.timestamps;
graphViews.chart().data.datasets[0].data = resp.views.amounts; graphViews.data().datasets[0].data = resp.views.amounts;
graphBandwidth.chart().data.labels = resp.views.timestamps; graphViews.data().datasets[1].data = resp.downloads.amounts;
graphBandwidth.chart().data.datasets[0].data = resp.bandwidth.amounts graphBandwidth.data().labels = resp.views.timestamps;
graphBandwidth.chart().data.datasets[1].data = resp.bandwidth_paid.amounts graphBandwidth.data().datasets[0].data = resp.bandwidth.amounts
graphBandwidth.data().datasets[1].data = resp.bandwidth_paid.amounts
graphViews.update() graphViews.update()
graphBandwidth.update() graphBandwidth.update()
@@ -107,7 +108,7 @@ function getStats(order) {
let statsInterval = null let statsInterval = null
onMount(() => { onMount(() => {
// Prepare chart datasets // Prepare chart datasets
graphBandwidth.chart().data.datasets = [ graphBandwidth.data().datasets = [
{ {
label: "Bandwidth (free)", label: "Bandwidth (free)",
borderWidth: 2, borderWidth: 2,
@@ -123,7 +124,7 @@ onMount(() => {
backgroundColor: "#"+window.style.dangerColor, backgroundColor: "#"+window.style.dangerColor,
}, },
]; ];
graphViews.chart().data.datasets = [ graphViews.data().datasets = [
{ {
label: "Views", label: "Views",
borderWidth: 2, borderWidth: 2,
@@ -131,6 +132,13 @@ onMount(() => {
borderColor: "#"+window.style.highlightColor, borderColor: "#"+window.style.highlightColor,
backgroundColor: "#"+window.style.highlightColor, backgroundColor: "#"+window.style.highlightColor,
}, },
{
label: "Downloads",
borderWidth: 2,
pointRadius: 0,
borderColor: "#"+window.style.dangerColor,
backgroundColor: "#"+window.style.dangerColor,
},
]; ];
loadGraph(10080, 10, false); loadGraph(10080, 10, false);
@@ -163,8 +171,8 @@ onDestroy(() => {
<button on:click={() => { loadGraph(525600, 1440, false) }}>Year</button> <button on:click={() => { loadGraph(525600, 1440, false) }}>Year</button>
<button on:click={() => { loadGraph(1051200, 1440, false) }}>Two Years</button> <button on:click={() => { loadGraph(1051200, 1440, false) }}>Two Years</button>
</div> </div>
<Chart bind:this={graphBandwidth} dataType="bytes" label="Bandwidth" /> <Chart bind:this={graphBandwidth} data_type="bytes" />
<Chart bind:this={graphViews} dataType="number" label="Views" /> <Chart bind:this={graphViews} data_type="number" />
<div class="highlight_dark"> <div class="highlight_dark">
Total usage from {start_time} to {end_time}<br/> Total usage from {start_time} to {end_time}<br/>
{formatDataVolume(total_bandwidth, 3)} bandwidth, {formatDataVolume(total_bandwidth, 3)} bandwidth,

View File

@@ -1,7 +1,8 @@
<script> <script>
import Chart from "../util/Chart.svelte"; import { onMount } from "svelte";
import { formatDataVolume, formatDate, formatThousands } from "../util/Formatting.svelte" import { formatDataVolume, formatDate, formatThousands } from "../util/Formatting.svelte"
import { domain_url } from "../util/Util.svelte"; import { domain_url } from "../util/Util.svelte";
import Chart from "../util/Chart.svelte";
export let file = { export let file = {
id: "", id: "",
@@ -16,24 +17,31 @@ export let file = {
timeseries_href: "", timeseries_href: "",
} }
let download_chart let chart
let view_chart let chart_timespan = 43200
let chart_interval = 60
$: update_charts(file.id) $: update_file(file.id)
let update_charts = () => { let update_file = id => {
if (file.id === "") { if (id) {
return update_chart(chart_timespan, chart_interval)
} }
}
let update_chart = (timespan, interval) => {
chart_timespan = timespan
chart_interval = interval
console.log("updating graph") console.log("updating graph")
let today = new Date()
let start = new Date() let start = new Date()
start.setDate(start.getDate() - 90) start.setMinutes(start.getMinutes() - timespan)
let end = new Date()
fetch( fetch(
file.timeseries_href + file.timeseries_href +
"?start=" + start.toISOString() + "?start=" + start.toISOString() +
"&end=" + today.toISOString() + "&end=" + end.toISOString() +
"&interval=" + 60 "&interval=" + 60
).then(resp => { ).then(resp => {
if (!resp.ok) { return null } if (!resp.ok) { return null }
@@ -41,10 +49,10 @@ let update_charts = () => {
}).then(resp => { }).then(resp => {
resp.views.timestamps.forEach((val, idx) => { resp.views.timestamps.forEach((val, idx) => {
let date = new Date(val); let date = new Date(val);
let dateStr = ("00" + (date.getMonth() + 1)).slice(-2); let str = ("00" + (date.getMonth() + 1)).slice(-2);
dateStr += "-" + ("00" + date.getDate()).slice(-2); str += "-" + ("00" + date.getDate()).slice(-2);
dateStr += " " + ("00" + date.getHours()).slice(-2) + "h"; str += " " + ("00" + date.getHours()).slice(-2) + "h";
resp.views.timestamps[idx] = " " + dateStr + " "; // Poor man's padding resp.views.timestamps[idx] = " " + str + " "; // Poor man's padding
}); });
resp.bandwidth.amounts.forEach((val, idx) => { resp.bandwidth.amounts.forEach((val, idx) => {
resp.bandwidth.amounts[idx] = Math.round(val / file.size); resp.bandwidth.amounts[idx] = Math.round(val / file.size);
@@ -52,14 +60,31 @@ let update_charts = () => {
resp.bandwidth_paid.amounts.forEach((val, idx) => { resp.bandwidth_paid.amounts.forEach((val, idx) => {
resp.bandwidth.amounts[idx] += Math.round(val / file.size); resp.bandwidth.amounts[idx] += Math.round(val / file.size);
}); });
download_chart.chart().data.labels = resp.views.timestamps chart.data().labels = resp.views.timestamps
view_chart.chart().data.labels = resp.views.timestamps chart.data().datasets[0].data = resp.views.amounts
download_chart.chart().data.datasets[0].data = resp.bandwidth.amounts chart.data().datasets[1].data = resp.bandwidth.amounts
view_chart.chart().data.datasets[0].data = resp.views.amounts chart.update()
download_chart.update()
view_chart.update()
}) })
} }
onMount(() => {
chart.data().datasets = [
{
label: "Views",
borderWidth: 2,
pointRadius: 0,
borderColor: "#"+window.style.highlightColor,
backgroundColor: "#"+window.style.highlightColor,
},
{
label: "Downloads",
borderWidth: 2,
pointRadius: 0,
borderColor: "#"+window.style.dangerColor,
backgroundColor: "#"+window.style.dangerColor,
},
];
})
</script> </script>
<div> <div>
@@ -126,10 +151,42 @@ let update_charts = () => {
{/if} {/if}
</table> </table>
<h2>Downloads</h2> <h2>Views and downloads</h2>
<Chart bind:this={download_chart} label="Downloads"></Chart>
<h2>Views</h2> <div class="button_bar">
<Chart bind:this={view_chart} label="Views"></Chart> <button
on:click={() => { update_chart(1440, 1) }}
class:button_highlight={chart_timespan == 1440}>
Day (1m)
</button>
<button
on:click={() => { update_chart(10080, 60) }}
class:button_highlight={chart_timespan == 10080}>
Week (1h)
</button>
<button
on:click={() => { update_chart(43200, 1440) }}
class:button_highlight={chart_timespan == 43200}>
Month (1d)
</button>
<button
on:click={() => { update_chart(131400, 1440) }}
class:button_highlight={chart_timespan == 131400}>
Quarter (1d)
</button>
<button
on:click={() => { update_chart(525600, 1440) }}
class:button_highlight={chart_timespan == 525600}>
Year (1d)
</button>
<button
on:click={() => { update_chart(1051200, 1440) }}
class:button_highlight={chart_timespan == 1051200}>
Two Years (1d)
</button>
</div>
<Chart bind:this={chart} />
<p style="text-align: center"> <p style="text-align: center">
Charts rendered by the amazing <a href="https://www.chartjs.org/" target="_blank">Chart.js</a>. Charts rendered by the amazing <a href="https://www.chartjs.org/" target="_blank">Chart.js</a>.
@@ -155,3 +212,11 @@ let update_charts = () => {
<tr><td>SHIFT + s</td><td> = Download all the files in the list as a zip archive</td></tr> <tr><td>SHIFT + s</td><td> = Download all the files in the list as a zip archive</td></tr>
</table> </table>
</div> </div>
<style>
.button_bar {
display: block;
width: 100%;
text-align: center;
}
</style>

View File

@@ -6,10 +6,8 @@ import StorageProgressBar from "./StorageProgressBar.svelte";
import HotlinkProgressBar from "./HotlinkProgressBar.svelte"; import HotlinkProgressBar from "./HotlinkProgressBar.svelte";
import Euro from "../util/Euro.svelte" import Euro from "../util/Euro.svelte"
let graph_view = null let graph_views_downloads = null
let graph_download = null
let graph_bandwidth = null let graph_bandwidth = null
let graph_transfer_paid = null
let time_start = "" let time_start = ""
let time_end = "" let time_end = ""
let total_views = 0 let total_views = 0
@@ -17,49 +15,73 @@ let total_downloads = 0
let total_bandwidth = 0 let total_bandwidth = 0
let total_transfer_paid = 0 let total_transfer_paid = 0
let load_graph = (graph, stat, minutes, interval) => { let load_graphs = async (minutes, interval) => {
let today = new Date() let end = new Date()
let start = new Date() let start = new Date()
start.setMinutes(start.getMinutes() - minutes) start.setMinutes(start.getMinutes() - minutes)
fetch( try {
let views = get_graph_data("views", start, end, interval);
let downloads = get_graph_data("downloads", start, end, interval);
let bandwidth = get_graph_data("bandwidth", start, end, interval);
let transfer_paid = get_graph_data("transfer_paid", start, end, interval);
views = await views
downloads = await downloads
bandwidth = await bandwidth
transfer_paid = await transfer_paid
graph_views_downloads.data().labels = views.timestamps;
graph_views_downloads.data().datasets[0].data = views.amounts
graph_views_downloads.data().datasets[1].data = downloads.amounts
graph_bandwidth.data().labels = bandwidth.timestamps;
graph_bandwidth.data().datasets[0].data = bandwidth.amounts
graph_bandwidth.data().datasets[1].data = transfer_paid.amounts
graph_views_downloads.update()
graph_bandwidth.update()
time_start = views.timestamps[0];
time_end = views.timestamps.slice(-1)[0];
} catch (err) {
console.error("Failed to update graphs", err)
return
}
}
let get_graph_data = async (stat, start, end, interval) => {
let resp = await fetch(
window.api_endpoint + "/user/time_series/" + stat + window.api_endpoint + "/user/time_series/" + stat +
"?start=" + start.toISOString() + "?start=" + start.toISOString() +
"&end=" + today.toISOString() + "&end=" + end.toISOString() +
"&interval=" + interval "&interval=" + interval
).then(resp => { )
if (!resp.ok) { return Promise.reject("Error: " + resp.status); } resp = await resp.json()
return resp.json();
}).then(resp => {
resp.timestamps.forEach((val, idx) => {
let date = new Date(val);
let dateStr = ("00" + (date.getMonth() + 1)).slice(-2);
dateStr += "-" + ("00" + date.getDate()).slice(-2);
dateStr += " " + ("00" + date.getHours()).slice(-2);
dateStr += ":" + ("00" + date.getMinutes()).slice(-2);
resp.timestamps[idx] = " " + dateStr + " "; // Poor man's padding
});
graph.chart().data.labels = resp.timestamps;
graph.chart().data.datasets[0].data = resp.amounts;
graph.chart().update();
time_start = resp.timestamps[0]; // Convert the timestamps to a human-friendly format
time_end = resp.timestamps.slice(-1)[0]; resp.timestamps.forEach((val, idx) => {
let date = new Date(val);
let str = ("00" + (date.getMonth() + 1)).slice(-2);
str += "-" + ("00" + date.getDate()).slice(-2);
str += " " + ("00" + date.getHours()).slice(-2);
str += ":" + ("00" + date.getMinutes()).slice(-2);
resp.timestamps[idx] = " " + str + " "; // Poor man's padding
});
let total = resp.amounts.reduce((acc, cur) => { return acc + cur }, 0) // Add up the total amount and save it in the correct place
let total = resp.amounts.reduce((acc, cur) => { return acc + cur }, 0)
if (stat == "views") { if (stat == "views") {
total_views = total; total_views = total;
} else if (stat == "downloads") { } else if (stat == "downloads") {
total_downloads = total; total_downloads = total;
} else if (stat == "bandwidth") { graph_views_downloads.update()
total_bandwidth = total; } else if (stat == "bandwidth") {
} else if (stat == "transfer_paid") { total_bandwidth = total;
total_transfer_paid = total; } else if (stat == "transfer_paid") {
} total_transfer_paid = total;
}).catch(e => { }
console.error("Error requesting time series: " + e);
}) return resp
} }
let graph_timeout = null let graph_timeout = null
@@ -72,10 +94,7 @@ let update_graphs = (minutes, interval, live) => {
graph_timespan = minutes graph_timespan = minutes
load_graph(graph_view, "views", minutes, interval) load_graphs(minutes, interval)
load_graph(graph_download, "downloads", minutes, interval)
load_graph(graph_bandwidth, "bandwidth", minutes, interval)
load_graph(graph_transfer_paid, "transfer_paid", minutes, interval)
load_direct_bw() load_direct_bw()
} }
@@ -113,6 +132,39 @@ onMount(() => {
transfer_cap = -1 transfer_cap = -1
} }
graph_views_downloads.data().datasets = [
{
label: "Views",
borderWidth: 2,
pointRadius: 0,
borderColor: "#"+window.style.highlightColor,
backgroundColor: "#"+window.style.highlightColor,
},
{
label: "Downloads",
borderWidth: 2,
pointRadius: 0,
borderColor: "#"+window.style.dangerColor,
backgroundColor: "#"+window.style.dangerColor,
},
];
graph_bandwidth.data().datasets = [
{
label: "Bandwidth (total)",
borderWidth: 2,
pointRadius: 0,
borderColor: "#"+window.style.highlightColor,
backgroundColor: "#"+window.style.highlightColor,
},
{
label: "Bandwidth (premium)",
borderWidth: 2,
pointRadius: 0,
borderColor: "#"+window.style.dangerColor,
backgroundColor: "#"+window.style.dangerColor,
},
];
update_graphs(1440, 1, true); update_graphs(1440, 1, true);
}) })
onDestroy(() => { onDestroy(() => {
@@ -235,43 +287,31 @@ onDestroy(() => {
{formatDataVolume(total_transfer_paid, 3)} paid transfers {formatDataVolume(total_transfer_paid, 3)} paid transfers
</div> </div>
<div class="limit_width"> <div class="limit_width">
<h3>Paid transfers</h3> <h3>Premium transfers and total bandwidth usage</h3>
<p> <p>
A paid transfer is when a file is downloaded using the data cap on A premium transfer is when a file is downloaded using the data cap
your subscription plan. These can be files you downloaded from other on your subscription plan. These can be files you downloaded from
people, or other people downloading your files if you have bandwidth other people, or other people downloading your files if you have
sharing enabled. Bandwidth sharing can be changed on bandwidth sharing enabled. Bandwidth sharing can be changed on
<a href="/user/subscription">the subscription page</a>. <a href="/user/subscription">the subscription page</a>.
</p> </p>
</div>
<Chart bind:this={graph_transfer_paid} dataType="bytes" label="Paid transfers" />
<div class="limit_width">
<h3>Views</h3>
<p> <p>
A view is counted when someone visits the download page of one Total bandwidth usage is the combined bandwidth usage of all the
of your files. Views are unique per user per file. files on your account. This includes paid transfers.
</p> </p>
</div> </div>
<Chart bind:this={graph_view} dataType="number" label="Views" /> <Chart bind:this={graph_bandwidth} data_type="bytes"/>
<div class="limit_width"> <div class="limit_width">
<h3>Downloads</h3> <h3>Views and downloads</h3>
<p> <p>
Downloads are counted when a user clicks the download button A view is counted when someone visits the download page of one of
on one of your files. It does not matter whether the your files. Views are unique per user per file.
download is completed or not, only the start of the download </p>
is counted. <p>
Downloads are counted when a user clicks the download button on one
of your files. It does not matter whether the download is completed
or not, only the start of the download is counted.
</p> </p>
</div> </div>
<Chart bind:this={graph_download} dataType="number" label="Downloads" /> <Chart bind:this={graph_views_downloads} data_type="number"/>
<div class="limit_width">
<h3>Bandwidth</h3>
<p>
This is how much bandwidth your files are using in total.
Bandwidth is used when a file is tranferred from a
pixeldrain server to a user who is downloading the file.
When a 5 MB file is downloaded 8 times it has used 40 MB of
bandwidth.
</p>
</div>
<Chart bind:this={graph_bandwidth} dataType="bytes" label="Bandwidth" />
</div> </div>

View File

@@ -5,12 +5,14 @@ import { Chart, PointElement, LineElement, LinearScale, CategoryScale, LineContr
let chart_element let chart_element
let chart_object let chart_object
export let label = "label" export let data_type = ""
export let dataType = ""
export const chart = () => { export const chart = () => {
return chart_object return chart_object
} }
export const data = () => {
return chart_object.data
}
export const update = () => { export const update = () => {
return chart_object.update() return chart_object.update()
} }
@@ -32,15 +34,8 @@ onMount(() => {
{ {
type: 'line', type: 'line',
data: { data: {
datasets: [ labels: [],
{ datasets: [],
label: label,
borderWidth: 0,
pointRadius: 0,
fill: 'origin',
backgroundColor: "#"+window.style.highlightColor,
}
]
}, },
options: { options: {
legend: { display: false }, legend: { display: false },
@@ -57,7 +52,7 @@ onMount(() => {
position: "left", position: "left",
ticks: { ticks: {
callback: function (value, index, values) { callback: function (value, index, values) {
if (dataType == "bytes") { if (data_type == "bytes") {
return formatDataVolume(value, 3); return formatDataVolume(value, 3);
} }
return formatNumber(value, 3); return formatNumber(value, 3);
@@ -88,7 +83,6 @@ onMount(() => {
} }
); );
}) })
</script> </script>
<div class="chart-container"> <div class="chart-container">