feat: enhance download tracking by adding speed history management in download slice

This commit is contained in:
Moyasee
2025-12-13 18:14:52 +02:00
parent 67f863e0f3
commit 67ea9e78a2
2 changed files with 28 additions and 63 deletions

View File

@@ -13,6 +13,7 @@ export interface DownloadState {
gamesWithDeletionInProgress: string[];
extraction: ExtractionInfo | null;
peakSpeeds: Record<string, number>;
speedHistory: Record<string, number[]>;
}
const initialState: DownloadState = {
@@ -21,6 +22,7 @@ const initialState: DownloadState = {
gamesWithDeletionInProgress: [],
extraction: null,
peakSpeeds: {},
speedHistory: {},
};
export const downloadSlice = createSlice({
@@ -31,13 +33,25 @@ export const downloadSlice = createSlice({
state.lastPacket = action.payload;
if (!state.gameId && action.payload) state.gameId = action.payload.gameId;
// Track peak speed atomically when packet arrives
// Track peak speed and speed history atomically when packet arrives
if (action.payload?.gameId && action.payload.downloadSpeed != null) {
const { gameId, downloadSpeed } = action.payload;
// Update peak speed if this is higher
const currentPeak = state.peakSpeeds[gameId] || 0;
if (downloadSpeed > currentPeak) {
state.peakSpeeds[gameId] = downloadSpeed;
}
// Update speed history for chart
if (!state.speedHistory[gameId]) {
state.speedHistory[gameId] = [];
}
state.speedHistory[gameId].push(downloadSpeed);
// Keep only last 120 entries
if (state.speedHistory[gameId].length > 120) {
state.speedHistory[gameId].shift();
}
}
},
clearDownload: (state) => {
@@ -85,6 +99,7 @@ export const downloadSlice = createSlice({
},
clearPeakSpeed: (state, action: PayloadAction<string>) => {
state.peakSpeeds[action.payload] = 0;
state.speedHistory[action.payload] = [];
},
},
});

View File

@@ -11,12 +11,10 @@ import { addMilliseconds } from "date-fns";
import { DOWNLOADER_NAME } from "@renderer/constants";
import {
useAppSelector,
useAppDispatch,
useDownload,
useLibrary,
useDate,
} from "@renderer/hooks";
import { clearPeakSpeed } from "@renderer/features";
import "./download-group.scss";
import { useTranslation } from "react-i18next";
@@ -514,9 +512,9 @@ export function DownloadGroup({
const { formatDistance } = useDate();
const dispatch = useAppDispatch();
// Get speed history and peak speeds from Redux (centralized state)
const speedHistory = useAppSelector((state) => state.download.speedHistory);
const peakSpeeds = useAppSelector((state) => state.download.peakSpeeds);
const speedHistoryRef = useRef<Record<string, number[]>>({});
const [dominantColors, setDominantColors] = useState<Record<string, string>>(
{}
);
@@ -579,62 +577,8 @@ export function DownloadGroup({
});
}, [library, lastPacket?.gameId]);
useEffect(() => {
if (!lastPacket?.gameId || lastPacket.downloadSpeed === undefined) return;
const gameId = lastPacket.gameId;
const downloadSpeed = lastPacket.downloadSpeed;
if (!speedHistoryRef.current[gameId]) {
speedHistoryRef.current[gameId] = [];
}
speedHistoryRef.current[gameId].push(downloadSpeed);
if (speedHistoryRef.current[gameId].length > 120) {
speedHistoryRef.current[gameId].shift();
}
}, [lastPacket]);
useEffect(() => {
for (const game of library) {
if (
game.download &&
game.download.progress < 0.01 &&
game.download.status !== "paused"
) {
// Fresh download - clear any old data
if (speedHistoryRef.current[game.id]?.length > 0) {
speedHistoryRef.current[game.id] = [];
dispatch(clearPeakSpeed(game.id));
}
}
}
}, [library, dispatch]);
useEffect(() => {
const timeouts: NodeJS.Timeout[] = [];
for (const game of library) {
if (
game.download?.progress === 1 &&
speedHistoryRef.current[game.id]?.length > 0
) {
const gameId = game.id;
const timeout = setTimeout(() => {
speedHistoryRef.current[gameId] = [];
dispatch(clearPeakSpeed(gameId));
}, 10_000);
timeouts.push(timeout);
}
}
return () => {
for (const timeout of timeouts) {
clearTimeout(timeout);
}
};
}, [library, dispatch]);
// Speed history and peak speeds are now tracked in Redux (in setLastPacket reducer)
// No local effect needed - data is updated atomically when packets arrive
useEffect(() => {
if (library.length > 0 && title === t("download_in_progress")) {
@@ -839,7 +783,13 @@ export function DownloadGroup({
? (lastPacket?.downloadSpeed ?? 0)
: 0;
const finalDownloadSize = getFinalDownloadSize(game);
const peakSpeed = peakSpeeds[game.id] || 0;
// Use lastPacket.gameId for lookup since that's the key used to store the data
// Fall back to game.id if lastPacket is not available
const dataKey = lastPacket?.gameId ?? game.id;
const gameSpeedHistory = speedHistory[dataKey] ?? [];
const storedPeak = peakSpeeds[dataKey];
// Use stored peak if available and > 0, otherwise use current speed as initial value
const peakSpeed = storedPeak !== undefined && storedPeak > 0 ? storedPeak : downloadSpeed;
let currentProgress = game.download?.progress || 0;
if (isGameExtracting) {
@@ -861,7 +811,7 @@ export function DownloadGroup({
currentProgress={currentProgress}
dominantColor={dominantColor}
lastPacket={lastPacket}
speedHistory={speedHistoryRef.current[game.id] || []}
speedHistory={gameSpeedHistory}
formatSpeed={formatSpeed}
calculateETA={calculateETA}
pauseDownload={pauseDownload}