mirror of
https://github.com/nimbold/Firelink.git
synced 2026-08-11 12:07:54 +00:00
feat(downloads): add live limits clipboard capture and byte progress
This commit is contained in:
@@ -55,6 +55,15 @@ const startDownloadListeners = async () => {
|
||||
if (shouldUpdateSize && current.size !== payload.size) {
|
||||
updates.size = payload.size!;
|
||||
}
|
||||
if (payload.downloaded_bytes !== null && payload.downloaded_bytes !== undefined) {
|
||||
updates.downloadedBytes = payload.downloaded_bytes;
|
||||
}
|
||||
if (payload.total_bytes !== null && payload.total_bytes !== undefined) {
|
||||
updates.totalBytes = payload.total_bytes;
|
||||
}
|
||||
if (payload.downloaded_bytes !== null && payload.downloaded_bytes !== undefined) {
|
||||
updates.totalIsEstimate = payload.total_is_estimate;
|
||||
}
|
||||
if (Object.keys(updates).length > 0) {
|
||||
mainStore.updateDownload(payload.id, updates);
|
||||
}
|
||||
|
||||
@@ -510,7 +510,7 @@ describe('useDownloadStore', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('uses the global speed limit only when an item has no explicit speed override', async () => {
|
||||
it('does not copy the global speed limit into a normal download task', async () => {
|
||||
const defaultSettings = useSettingsStore.getState();
|
||||
vi.mocked(useSettingsStore.getState).mockReturnValue({
|
||||
...defaultSettings,
|
||||
@@ -534,6 +534,37 @@ describe('useDownloadStore', () => {
|
||||
expect.objectContaining({
|
||||
item: expect.objectContaining({
|
||||
id: 'inherits-global',
|
||||
speed_limit: null
|
||||
})
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('passes the global speed limit to a new media process when it has no item override', async () => {
|
||||
const defaultSettings = useSettingsStore.getState();
|
||||
vi.mocked(useSettingsStore.getState).mockReturnValue({
|
||||
...defaultSettings,
|
||||
globalSpeedLimit: '2M'
|
||||
});
|
||||
vi.mocked(ipc.invokeCommand).mockImplementation(async (cmd: string) => {
|
||||
if (cmd === 'get_pending_order') return ['inherits-global-media'];
|
||||
return undefined;
|
||||
});
|
||||
|
||||
await useDownloadStore.getState().addDownload({
|
||||
id: 'inherits-global-media',
|
||||
url: 'https://www.youtube.com/watch?v=example',
|
||||
fileName: 'media.mp4',
|
||||
category: 'Movies',
|
||||
dateAdded: '',
|
||||
isMedia: true
|
||||
}, { type: 'start-now' });
|
||||
|
||||
expect(ipc.invokeCommand).toHaveBeenCalledWith(
|
||||
'enqueue_download',
|
||||
expect.objectContaining({
|
||||
item: expect.objectContaining({
|
||||
id: 'inherits-global-media',
|
||||
speed_limit: '2M'
|
||||
})
|
||||
})
|
||||
|
||||
@@ -134,11 +134,21 @@ const stripCookieHeaders = (value: string | null | undefined): string =>
|
||||
.join('\n')
|
||||
.trim();
|
||||
|
||||
const speedLimitForDispatch = (itemSpeedLimit: string | undefined, globalSpeedLimit: string): string | null => {
|
||||
const explicitSpeedLimitForDispatch = (itemSpeedLimit: string | undefined): string | null => {
|
||||
const explicitLimit = itemSpeedLimit?.trim();
|
||||
if (explicitLimit) {
|
||||
return normalizeSpeedLimitForBackend(explicitLimit) || (explicitLimit === '0' ? '0' : null);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const speedLimitForDispatch = (
|
||||
itemSpeedLimit: string | undefined,
|
||||
globalSpeedLimit: string,
|
||||
isMedia: boolean | undefined
|
||||
): string | null => {
|
||||
const explicitLimit = explicitSpeedLimitForDispatch(itemSpeedLimit);
|
||||
if (explicitLimit !== null || !isMedia) return explicitLimit;
|
||||
return normalizeSpeedLimitForBackend(globalSpeedLimit);
|
||||
};
|
||||
|
||||
@@ -186,7 +196,7 @@ export async function dispatchItem(id: string): Promise<boolean> {
|
||||
destination,
|
||||
filename: item.fileName,
|
||||
connections: item.connections || settings.perServerConnections || null,
|
||||
speed_limit: speedLimitForDispatch(item.speedLimit, settings.globalSpeedLimit),
|
||||
speed_limit: speedLimitForDispatch(item.speedLimit, settings.globalSpeedLimit, item.isMedia),
|
||||
username: item.username || (login ? login.username : null),
|
||||
password: item.password || keychainPassword,
|
||||
headers: item.headers || null,
|
||||
@@ -842,6 +852,9 @@ export const useDownloadStore = create<DownloadState>((set, get) => ({
|
||||
fraction: 0,
|
||||
speed: '-',
|
||||
eta: '-',
|
||||
downloadedBytes: undefined,
|
||||
totalBytes: undefined,
|
||||
totalIsEstimate: undefined,
|
||||
hasBeenDispatched: false,
|
||||
dateAdded: new Date().toISOString()
|
||||
});
|
||||
@@ -1159,7 +1172,7 @@ export const useDownloadStore = create<DownloadState>((set, get) => ({
|
||||
destination: destPath,
|
||||
filename: item.fileName,
|
||||
connections: item.connections || settings.perServerConnections || null,
|
||||
speed_limit: speedLimitForDispatch(item.speedLimit, settings.globalSpeedLimit),
|
||||
speed_limit: speedLimitForDispatch(item.speedLimit, settings.globalSpeedLimit, item.isMedia),
|
||||
username: item.username || (login ? login.username : null),
|
||||
password: item.password || keychainPassword,
|
||||
headers: item.headers || null,
|
||||
|
||||
@@ -143,6 +143,7 @@ export interface SettingsState {
|
||||
maxAutomaticRetries: number;
|
||||
showNotifications: boolean;
|
||||
playCompletionSound: boolean;
|
||||
autoAddClipboardLinks: boolean;
|
||||
appFontSize: AppFontSize;
|
||||
listRowDensity: ListRowDensity;
|
||||
showDockBadge: boolean;
|
||||
@@ -186,6 +187,7 @@ export interface SettingsState {
|
||||
setMaxAutomaticRetries: (count: number) => void;
|
||||
setShowNotifications: (show: boolean) => void;
|
||||
setPlayCompletionSound: (play: boolean) => void;
|
||||
setAutoAddClipboardLinks: (enabled: boolean) => void;
|
||||
setAppFontSize: (size: AppFontSize) => void;
|
||||
setListRowDensity: (density: ListRowDensity) => void;
|
||||
setShowDockBadge: (show: boolean) => void;
|
||||
@@ -250,6 +252,7 @@ export const useSettingsStore = create<SettingsState>()(
|
||||
maxAutomaticRetries: 3,
|
||||
showNotifications: true,
|
||||
playCompletionSound: false,
|
||||
autoAddClipboardLinks: false,
|
||||
appFontSize: 'standard',
|
||||
listRowDensity: 'standard',
|
||||
showDockBadge: true,
|
||||
@@ -319,6 +322,7 @@ export const useSettingsStore = create<SettingsState>()(
|
||||
}),
|
||||
setShowNotifications: (showNotifications) => set({ showNotifications }),
|
||||
setPlayCompletionSound: (playCompletionSound) => set({ playCompletionSound }),
|
||||
setAutoAddClipboardLinks: (autoAddClipboardLinks) => set({ autoAddClipboardLinks }),
|
||||
setAppFontSize: (appFontSize) => set({ appFontSize }),
|
||||
setListRowDensity: (listRowDensity) => set({ listRowDensity }),
|
||||
setShowDockBadge: (showDockBadge) => {
|
||||
@@ -477,6 +481,7 @@ export const useSettingsStore = create<SettingsState>()(
|
||||
maxAutomaticRetries: state.maxAutomaticRetries,
|
||||
showNotifications: state.showNotifications,
|
||||
playCompletionSound: state.playCompletionSound,
|
||||
autoAddClipboardLinks: state.autoAddClipboardLinks,
|
||||
appFontSize: state.appFontSize,
|
||||
listRowDensity: state.listRowDensity,
|
||||
showDockBadge: state.showDockBadge,
|
||||
@@ -525,6 +530,10 @@ export const useSettingsStore = create<SettingsState>()(
|
||||
: currentState.activeSettingsTab,
|
||||
showNotifications: persistedBoolean(persisted.showNotifications, currentState.showNotifications),
|
||||
playCompletionSound: persistedBoolean(persisted.playCompletionSound, currentState.playCompletionSound),
|
||||
autoAddClipboardLinks: persistedBoolean(
|
||||
persisted.autoAddClipboardLinks,
|
||||
currentState.autoAddClipboardLinks
|
||||
),
|
||||
showDockBadge: persistedBoolean(persisted.showDockBadge, currentState.showDockBadge),
|
||||
showMenuBarIcon: persistedBoolean(persisted.showMenuBarIcon, currentState.showMenuBarIcon),
|
||||
askWhereToSaveEachFile: persistedBoolean(
|
||||
|
||||
Reference in New Issue
Block a user