From 9bd41b5f00b69c01e73e3694d2a433e65071c4c2 Mon Sep 17 00:00:00 2001 From: Cory Gross Date: Fri, 16 Sep 2022 14:34:31 +0000 Subject: [PATCH 1/3] Handle PWA launches for both magnet urls and torrent files --- .../src/javascript/components/AppWrapper.tsx | 22 ++++++++++++ .../general/form-elements/FileDropzone.tsx | 25 ++++--------- .../add-torrents-modal/AddTorrentsByFile.tsx | 2 +- .../torrent-list/TorrentListDropzone.tsx | 26 ++++---------- client/src/javascript/util/fileProcessor.ts | 36 +++++++++++++++++++ client/src/public/manifest.json | 21 ++++++++++- 6 files changed, 92 insertions(+), 40 deletions(-) create mode 100644 client/src/javascript/util/fileProcessor.ts diff --git a/client/src/javascript/components/AppWrapper.tsx b/client/src/javascript/components/AppWrapper.tsx index fd0404a35..fa4912a2b 100644 --- a/client/src/javascript/components/AppWrapper.tsx +++ b/client/src/javascript/components/AppWrapper.tsx @@ -12,6 +12,7 @@ import AuthStore from '@client/stores/AuthStore'; import ConfigStore from '@client/stores/ConfigStore'; import ClientStatusStore from '@client/stores/ClientStatusStore'; import UIStore from '@client/stores/UIStore'; +import { processFiles } from '@client/util/fileProcessor' import ClientConnectionInterruption from './general/ClientConnectionInterruption'; import WindowTitle from './general/WindowTitle'; @@ -23,6 +24,16 @@ interface AppWrapperProps { className?: string; } +declare global { + interface Window { + launchQueue: { + setConsumer(consumer: (launchParams: { + files: FileSystemFileHandle[] + }) => any): void; + }; + } +} + const AppWrapper: FC = observer(({children, className}: AppWrapperProps) => { const navigate = useNavigate(); @@ -55,6 +66,17 @@ const AppWrapper: FC = observer(({children, className}: AppWrap } } + if ('launchQueue' in window) { + window.launchQueue.setConsumer(async (launchParams) => { + if (launchParams.files && launchParams.files.length) { + const processedFiles = await processFiles(launchParams.files); + if (processedFiles.length) { + UIStore.setActiveModal({ id: 'add-torrents', tab: 'by-file', files: processedFiles }); + } + } + }); + } + let overlay: ReactNode = null; if (!AuthStore.isAuthenticating || (AuthStore.isAuthenticated && !UIStore.haveUIDependenciesResolved)) { overlay = ; diff --git a/client/src/javascript/components/general/form-elements/FileDropzone.tsx b/client/src/javascript/components/general/form-elements/FileDropzone.tsx index 3f72e7fc6..c8cc38da0 100644 --- a/client/src/javascript/components/general/form-elements/FileDropzone.tsx +++ b/client/src/javascript/components/general/form-elements/FileDropzone.tsx @@ -5,7 +5,8 @@ import {Trans} from '@lingui/react'; import {Close, File, Files} from '@client/ui/icons'; import {FormRowItem} from '@client/ui'; -export type ProcessedFiles = Array<{name: string; data: string}>; +import type { ProcessedFiles } from '@client/util/fileProcessor'; +import { processFiles } from '@client/util/fileProcessor' interface FileDropzoneProps { initialFiles?: ProcessedFiles; @@ -55,23 +56,11 @@ const FileDropzone: FC = ({initialFiles, onFilesChanged}: Fil ) : null} ) => { - const processedFiles: ProcessedFiles = []; - addedFiles.forEach((file) => { - const reader = new FileReader(); - reader.onload = (e) => { - if (e.target?.result != null && typeof e.target.result === 'string') { - processedFiles.push({ - name: file.name, - data: e.target.result.split('base64,')[1], - }); - } - if (processedFiles.length === addedFiles.length) { - setFiles(files.concat(processedFiles)); - } - }; - reader.readAsDataURL(file); - }); + onDrop={async (addedFiles: Array) => { + const processedFiles = await processFiles(addedFiles); + if (processedFiles.length) { + setFiles(files.concat(processedFiles)); + } }} > {({getRootProps, getInputProps, isDragActive}) => ( diff --git a/client/src/javascript/components/modals/add-torrents-modal/AddTorrentsByFile.tsx b/client/src/javascript/components/modals/add-torrents-modal/AddTorrentsByFile.tsx index d07b9054a..ca47b4c65 100644 --- a/client/src/javascript/components/modals/add-torrents-modal/AddTorrentsByFile.tsx +++ b/client/src/javascript/components/modals/add-torrents-modal/AddTorrentsByFile.tsx @@ -12,7 +12,7 @@ import FileDropzone from '../../general/form-elements/FileDropzone'; import FilesystemBrowserTextbox from '../../general/form-elements/FilesystemBrowserTextbox'; import TagSelect from '../../general/form-elements/TagSelect'; -import type {ProcessedFiles} from '../../general/form-elements/FileDropzone'; +import type {ProcessedFiles} from '@client/util/fileProcessor'; interface AddTorrentsByFileFormData { destination: string; diff --git a/client/src/javascript/components/torrent-list/TorrentListDropzone.tsx b/client/src/javascript/components/torrent-list/TorrentListDropzone.tsx index b7aa48356..1868a181b 100644 --- a/client/src/javascript/components/torrent-list/TorrentListDropzone.tsx +++ b/client/src/javascript/components/torrent-list/TorrentListDropzone.tsx @@ -3,27 +3,13 @@ import {useDropzone} from 'react-dropzone'; import UIStore from '@client/stores/UIStore'; -import type {ProcessedFiles} from '@client/components/general/form-elements/FileDropzone'; +import { processFiles } from '@client/util/fileProcessor'; -const handleFileDrop = (files: Array) => { - const processedFiles: ProcessedFiles = []; - - files.forEach((file) => { - const reader = new FileReader(); - reader.onload = (e) => { - if (e.target?.result != null && typeof e.target.result === 'string') { - processedFiles.push({ - name: file.name, - data: e.target.result.split('base64,')[1], - }); - } - - if (processedFiles.length === files.length && processedFiles[0] != null) { - UIStore.setActiveModal({id: 'add-torrents', tab: 'by-file', files: processedFiles}); - } - }; - reader.readAsDataURL(file); - }); +const handleFileDrop = async (files: Array) => { + const processedFiles = await processFiles(files); + if (processedFiles.length) { + UIStore.setActiveModal({ id: 'add-torrents', tab: 'by-file', files: processedFiles }); + } }; const TorrentListDropzone: FC<{children: ReactNode}> = ({children}: {children: ReactNode}) => { diff --git a/client/src/javascript/util/fileProcessor.ts b/client/src/javascript/util/fileProcessor.ts new file mode 100644 index 000000000..5d9fc14c0 --- /dev/null +++ b/client/src/javascript/util/fileProcessor.ts @@ -0,0 +1,36 @@ +interface ProcessedFile { name: string; data: string } + +function processFile(file: File): Promise { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.addEventListener('loadend', ({ target }) => { + const result = target?.result as string; + if (result && typeof result === 'string') { + resolve({ + name: file?.name, + data: result.split('base64,')[1] + }); + } else { + reject(new Error(`Error reading file: ${file?.name}`)); + } + }); + reader.readAsDataURL(file); + }); +} + +export type ProcessedFiles = Array; +export async function processFiles(fileList: File[] | FileSystemFileHandle[]): Promise { + const processedFiles = []; + for (let file of fileList) { + try { + if (file instanceof FileSystemFileHandle) { + file = await file.getFile(); + } + const processedFile = await processFile(file); + processedFiles.push(processedFile); + } catch(error) { + console.error(error); + } + } + return processedFiles; +} \ No newline at end of file diff --git a/client/src/public/manifest.json b/client/src/public/manifest.json index c31b0f31d..4c5cea5e6 100644 --- a/client/src/public/manifest.json +++ b/client/src/public/manifest.json @@ -40,7 +40,26 @@ "name": "Flood", "short_name": "Flood", "display": "standalone", - "start_url": "./index.html", + "protocol_handlers": [ + { + "protocol": "magnet", + "url": "/?action=add-urls&url=%s" + } + ], + "file_handlers": [ + { + "name": "Torrent", + "action": "/?action=add-files", + "accept": { + "application/x-bittorrent": [".torrent"] + }, + "launch_type": "single-client" + } + ], + "launch_handler": { + "route_to": "existing-client-navigate" + }, + "start_url": "/", "description": "Web UI for torrent clients", "background_color": "#ffffff", "theme_color": "#349cf4" From b49a8d5a984385b105379502ec3ae045602aa617 Mon Sep 17 00:00:00 2001 From: Cory Gross Date: Fri, 16 Sep 2022 17:26:50 +0000 Subject: [PATCH 2/3] Add file handling icon in manifest for PWA file handler --- client/src/public/icon_144x144.png | Bin 0 -> 8042 bytes client/src/public/manifest.json | 9 ++++++++- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 client/src/public/icon_144x144.png diff --git a/client/src/public/icon_144x144.png b/client/src/public/icon_144x144.png new file mode 100644 index 0000000000000000000000000000000000000000..d099f9940f087f5ec415d160fbddce89ce52b347 GIT binary patch literal 8042 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 Date: Wed, 30 Nov 2022 19:37:04 -0800 Subject: [PATCH 3/3] Launch_handler use client_mode navigate-existing --- client/src/public/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/public/manifest.json b/client/src/public/manifest.json index 07ecc89a7..73f2b6e36 100644 --- a/client/src/public/manifest.json +++ b/client/src/public/manifest.json @@ -64,7 +64,7 @@ } ], "launch_handler": { - "route_to": "existing-client-navigate" + "client_mode": "navigate-existing" }, "start_url": "/", "description": "Web UI for torrent clients",