diff --git a/api/src/main/java/telegram/files/TelegramVerticle.java b/api/src/main/java/telegram/files/TelegramVerticle.java index e12a958..e3a7b5d 100644 --- a/api/src/main/java/telegram/files/TelegramVerticle.java +++ b/api/src/main/java/telegram/files/TelegramVerticle.java @@ -410,7 +410,27 @@ public class TelegramVerticle extends AbstractVerticle { } public Future getDownloadStatistics() { - return DataVerticle.fileRepository.getDownloadStatistics(this.telegramRecord.id()); + return Future.all(DataVerticle.fileRepository.getDownloadStatistics(this.telegramRecord.id()), + this.execute(new TdApi.GetNetworkStatistics()) + ).map(r -> { + JsonObject jsonObject = r.resultAt(0); + TdApi.NetworkStatistics networkStatistics = r.resultAt(1); + Tuple2 bytes = Arrays.stream(networkStatistics.entries) + .filter(e -> e instanceof TdApi.NetworkStatisticsEntryFile) + .map(e -> { + TdApi.NetworkStatisticsEntryFile entry = (TdApi.NetworkStatisticsEntryFile) e; + return Tuple.tuple(entry.sentBytes, entry.receivedBytes); + }) + .reduce((a, b) -> Tuple.tuple(a.v1 + b.v1, a.v2 + b.v2)) + .orElse(Tuple.tuple(0L, 0L)); + + jsonObject.put("networkStatistics", JsonObject.of() + .put("sinceDate", networkStatistics.sinceDate) + .put("sentBytes", bytes.v1) + .put("receivedBytes", bytes.v2) + ); + return jsonObject; + }); } public Future enableProxy(String proxyName) { diff --git a/web/src/components/file-statistics.tsx b/web/src/components/file-statistics.tsx index 611e009..fe96750 100644 --- a/web/src/components/file-statistics.tsx +++ b/web/src/components/file-statistics.tsx @@ -2,16 +2,20 @@ import React from "react"; import useSWR from "swr"; import { AlertTriangle, - CheckCircle, CloudDownload, + CheckCircle, + CloudDownload, Download, File, FileText, Image, Music, - PauseCircle, + Network, + PauseCircle, Upload, Video, } from "lucide-react"; -import { request } from "@/lib/api"; // Define a fetcher function to handle the API request +import { request } from "@/lib/api"; +import prettyBytes from "pretty-bytes"; +import { formatDistanceToNow } from "date-fns"; // Define a fetcher function to handle the API request // Interface defining the structure of the data returned from the API interface StatisticsData { @@ -24,6 +28,11 @@ interface StatisticsData { video: number; audio: number; file: number; + networkStatistics: { + sinceDate: number; + sentBytes: number; + receivedBytes: number; + }; } // Props interface for the component, expecting a telegramId as input @@ -100,8 +109,10 @@ const FileStatistics: React.FC = ({ telegramId }) => {
- -

Download Statistics

+

+ + Download Statistics +

@@ -109,7 +120,7 @@ const FileStatistics: React.FC = ({ telegramId }) => { Total Files
-
+
{total}
@@ -118,7 +129,7 @@ const FileStatistics: React.FC = ({ telegramId }) => { Downloading
-
+
{downloading}
@@ -127,7 +138,7 @@ const FileStatistics: React.FC = ({ telegramId }) => { Paused
-
+
{paused}
@@ -136,7 +147,7 @@ const FileStatistics: React.FC = ({ telegramId }) => { Completed
-
+
{completed}
@@ -145,34 +156,65 @@ const FileStatistics: React.FC = ({ telegramId }) => { Error -
+
{errorCount}
-
-

- - Completed by Type -

-
    - {completedTypes.map((type) => ( -
  • -
    - {type.icon} - {type.label} -
    -
    - {type.value} -
    -
  • - ))} -
+
+
+

+ + Completed by Type +

+
    + {completedTypes.map((type) => ( +
  • +
    + {type.icon} + {type.label} +
    +
    + {type.value} +
    +
  • + ))} +
+
+ +
+

+ + Network Statistics +

+
+
+ + + {prettyBytes(data.networkStatistics.sentBytes)} + +
+
+ + + {prettyBytes(data.networkStatistics.receivedBytes)} + +
+

+ Since: {formatDistanceToNow( + new Date(data.networkStatistics.sinceDate * 1000), + { + addSuffix: true, + }, + )} +

+
+
); diff --git a/web/src/components/settings-dialog.tsx b/web/src/components/settings-dialog.tsx index 75bc5ed..32ff1dc 100644 --- a/web/src/components/settings-dialog.tsx +++ b/web/src/components/settings-dialog.tsx @@ -53,7 +53,7 @@ export const SettingsDialog: React.FC = () => { -
+
{accountId ? ( ) : (