diff --git a/crates/librqbit/webui/src/index.tsx b/crates/librqbit/webui/src/index.tsx
index 835bd0e..61753ea 100644
--- a/crates/librqbit/webui/src/index.tsx
+++ b/crates/librqbit/webui/src/index.tsx
@@ -93,41 +93,56 @@ interface TorrentStats {
};
time_remaining: {
human_readable: string;
+ duration: {
+ secs: number,
+ }
} | null;
}
const TorrentRow: React.FC<{
- detailsResponse: TorrentDetails, statsResponse: TorrentStats
-}> = ({ detailsResponse, statsResponse }) => {
+ id: number, detailsResponse: TorrentDetails, statsResponse: TorrentStats
+}> = ({ id, detailsResponse, statsResponse }) => {
const totalBytes = statsResponse.snapshot.total_bytes;
const downloadedBytes = statsResponse.snapshot.have_bytes;
const finished = totalBytes == downloadedBytes;
const downloadPercentage = (downloadedBytes / totalBytes) * 100;
+ let classes = [
+ ];
+ if (id % 2 == 0) {
+ classes.push('bg-light');
+ }
+
return (
-
- {getLargestFileName(detailsResponse)}
- {`${formatBytes(totalBytes)}`}
-
-
+
+
+
+ {getLargestFileName(detailsResponse)}
+
- {statsResponse.download_speed.human_readable}
+ {`${formatBytes(totalBytes)}`}
+
+
+
+ {statsResponse.download_speed.human_readable}
{getCompletionETA(statsResponse)}
- {`${statsResponse.snapshot.peer_stats.live} / ${statsResponse.snapshot.peer_stats.seen}`}
-
+ {`${statsResponse.snapshot.peer_stats.live} / ${statsResponse.snapshot.peer_stats.seen}`}
+
);
}
const Column: React.FC<{
label: string,
+ size?: number,
children?: any
-}> = ({ children }) => (
-
+}> = ({ size, label, children }) => (
+
+ {label}
{children}
- |
+
);
-const Torrent = ({ torrent }) => {
+const Torrent = ({ id, torrent }) => {
const defaultDetails: TorrentDetails = {
info_hash: '',
files: []
@@ -202,7 +217,7 @@ const Torrent = ({ torrent }) => {
return clear;
}, []);
- return
+ return
}
const TorrentsList = (props: { torrents: Array, loading: boolean }) => {
@@ -222,24 +237,11 @@ const TorrentsList = (props: { torrents: Array, loading: boolean }) =
)
}
return (
-
-
-
- | Name |
- Size |
- Progress |
- Download Speed |
- ETA |
- Peers |
-
-
-
- {props.torrents.map((t: TorrentId) =>
-
- )}
-
-
-
+ <>
+ {props.torrents.map((t: TorrentId) =>
+
+ )}
+ >
)
};
@@ -334,14 +336,14 @@ const Root = () => {
}
return
-
+
rqbit web 0.0.1-alpha
-
+
}
@@ -608,13 +610,29 @@ function getLargestFileName(torrentDetails: TorrentDetails): string {
// Function to get the completion ETA of a torrent
function getCompletionETA(stats: TorrentStats): string {
- if (stats.time_remaining) {
- return stats.time_remaining.human_readable;
+ if (stats.time_remaining && stats.time_remaining.duration) {
+ return formatSecondsToTime(stats.time_remaining.duration.secs);
} else {
return 'N/A';
}
}
+function formatSecondsToTime(seconds: number) {
+ const hours = Math.floor(seconds / 3600);
+ const minutes = Math.floor((seconds % 3600) / 60);
+ const remainingSeconds = seconds % 60;
+
+ const formatUnit = (value, unit) => (value > 0 ? `${value}${unit}` : '');
+
+ if (hours > 0) {
+ return `${formatUnit(hours, 'h')} ${formatUnit(minutes, 'm')}`.trim();
+ } else if (minutes > 0) {
+ return `${formatUnit(minutes, 'm')} ${formatUnit(remainingSeconds, 's')}`.trim();
+ } else {
+ return `${formatUnit(remainingSeconds, 's')}`.trim();
+ }
+}
+
function customSetInterval(asyncCallback: any, interval: number) {
let timeoutId: number;
let currentInterval: number = interval;