From cc958581bf39239eb8f3a91e9ef2ce2597c42ae1 Mon Sep 17 00:00:00 2001 From: E44 <129310925+programmer-44@users.noreply.github.com> Date: Mon, 5 Jan 2026 22:45:00 +0100 Subject: [PATCH] chore(control): add download function --- .../src/lib/ts/file_transfer_handler.ts | 105 +++++++++++++----- control/frontend/src/routes/FileView.svelte | 14 ++- 2 files changed, 90 insertions(+), 29 deletions(-) diff --git a/control/frontend/src/lib/ts/file_transfer_handler.ts b/control/frontend/src/lib/ts/file_transfer_handler.ts index 8090278..37ab3c5 100644 --- a/control/frontend/src/lib/ts/file_transfer_handler.ts +++ b/control/frontend/src/lib/ts/file_transfer_handler.ts @@ -2,6 +2,7 @@ import { db } from './files_display.db'; import { get_display_by_id } from './stores/displays'; import { get_current_folder_elements, + get_file_by_id, remove_all_files_without_display, remove_file_from_display } from './stores/files'; @@ -83,6 +84,39 @@ export async function add_upload( await start_task_processing(); } +export async function add_download(selected_file_id: string) { + const active_displays = await db.displays.toArray(); //TODO: where('status').equals('app_online').toArray(); + const active_display_ids = active_displays.map((e) => e.id); + + const file_on_display = await db.files_on_display + .where('file_primary_key') + .equals(selected_file_id) + .filter((e) => active_display_ids.includes(e.display_id)) + .first(); + if (!file_on_display) return; + + const display_ip = active_displays.find((e) => e.id === file_on_display.display_id)?.ip; + if (!display_ip) return; + const file = await get_file_by_id(selected_file_id); + if (!file) return; + + tasks.push({ + data: { + type: 'download' + }, + display: { + id: file_on_display.display_id, + ip: display_ip + }, + path: file.path, + file_name: file.name, + file_primary_key: selected_file_id, + bytes_total: file.size + }); + + await start_task_processing(); +} + function generate_valid_file_name(original_file_name: string, used_file_names: string[]): string { const regex = /\s\((\d{1,3})\)$/; @@ -96,39 +130,13 @@ function generate_valid_file_name(original_file_name: string, used_file_names: s } else { const match = name_without_extension.match(regex); const current_number: number = match ? Number(match[1]) : 0; - console.log('current', current_number); name_without_extension = name_without_extension.replace(regex, ` (${current_number + 1})`); } name = name_without_extension + extension; - console.log(name); } return name; } -async function start_task_processing() { - if (!is_processing) { - is_processing = tasks.length !== 0; - await start_task_loop(); - } -} - -async function start_task_loop() { - while (tasks.length > 0) { - const current_task = tasks[0]; - switch (current_task.data.type) { - case 'upload': - await upload(current_task); - break; - case 'download': - break; - case 'sync': - break; - } - tasks.shift(); // Remove current_task from tasks - } - is_processing = false; -} - async function upload(task: FileTransferTask): Promise { const task_data = task.data; if (task_data.type !== 'upload' || !task_data.file) return; @@ -194,6 +202,51 @@ async function upload(task: FileTransferTask): Promise { }); } +async function download(task: FileTransferTask): Promise { + if (task.data.type !== 'download') return; + + try { + // TODO: Update File_on_display.loading_data -> start + const url = `http://${task.display.ip}:1323/api${get_sanitized_file_url(task.path + task.file_name)}`; + + const a = document.createElement('a'); + a.href = url; + a.download = task.file_name; // Hint für den Browser (Server-Header ist trotzdem besser) + a.rel = 'noopener'; + document.body.appendChild(a); + a.click(); + a.remove(); + // TODO: Update File_on_display.loading_data -> finish + } catch (e) { + show_error(task, String(e)); + } +} + +async function start_task_processing() { + if (!is_processing) { + is_processing = tasks.length !== 0; + await start_task_loop(); + } +} + +async function start_task_loop() { + while (tasks.length > 0) { + console.log('NOCH', tasks.length, 'ZU TUN'); + const current_task = tasks[0]; + switch (current_task.data.type) { + case 'upload': + await upload(current_task); + break; + case 'download': + await download(current_task); + break; + case 'sync': + break; + } + tasks.shift(); // Remove current_task from tasks + } + is_processing = false; +} function get_prognosed_data( start_time: Date, diff --git a/control/frontend/src/routes/FileView.svelte b/control/frontend/src/routes/FileView.svelte index b25f8ca..082d205 100755 --- a/control/frontend/src/routes/FileView.svelte +++ b/control/frontend/src/routes/FileView.svelte @@ -37,7 +37,7 @@ import { delete_files, rename_file } from '$lib/ts/api_handler'; import HighlightedText from '$lib/components/HighlightedText.svelte'; import { liveQuery, type Observable } from 'dexie'; - import { add_upload } from '$lib/ts/file_transfer_handler'; + import { add_download, add_upload } from '$lib/ts/file_transfer_handler'; let current_name: string = $state(''); let current_valid: boolean = $state(false); @@ -54,6 +54,13 @@ display_ids = $selected_display_ids; current_folder_elements = liveQuery(() => get_current_folder_elements(path, display_ids)); }); + let one_file_selected: Observable | undefined = $state(); + $effect(() => { + const s = $selected_file_ids; + one_file_selected = liveQuery(async () => { + return s.length === 1 && (await get_file_by_id(s[0]))?.type !== 'inode/directory'; + }) + }) let popup_content: PopupContent = $state({ open: false, @@ -311,9 +318,10 @@ disabled={$selected_display_ids.length === 0}> (add_download($selected_file_ids[0]))} + disabled={!$one_file_selected ?? true}>