From 28170eab5d91c3a710261e84619281b187f99345 Mon Sep 17 00:00:00 2001 From: Jordan Fearnley Date: Sun, 24 Nov 2024 19:48:44 +0000 Subject: [PATCH] Feat: Add buttons to copy the ED2K hash to the clipboard in the link format --- src/components/FileInfo.tsx | 20 +++++++++++++++++-- .../Utilities/Unrecognized/AvDumpFileIcon.tsx | 9 ++------- src/core/utilities/getEd2kLink.ts | 6 ++++++ src/pages/utilities/FileSearch.tsx | 16 ++++++++++++++- .../UnrecognizedTab.tsx | 6 ++---- 5 files changed, 43 insertions(+), 14 deletions(-) create mode 100644 src/core/utilities/getEd2kLink.ts diff --git a/src/components/FileInfo.tsx b/src/components/FileInfo.tsx index e8454ef3d..309ff9a5d 100644 --- a/src/components/FileInfo.tsx +++ b/src/components/FileInfo.tsx @@ -1,6 +1,11 @@ -import React from 'react'; +import React, { useMemo } from 'react'; +import { mdiClipboardOutline } from '@mdi/js'; +import Icon from '@mdi/react'; import prettyBytes from 'pretty-bytes'; +import { copyToClipboard } from '@/core/util'; +import getEd2kLink from '@/core/utilities/getEd2kLink'; +import useEventCallback from '@/hooks/useEventCallback'; import useMediaInfo from '@/hooks/useMediaInfo'; import type { FileType } from '@/core/types/api/file'; @@ -8,6 +13,12 @@ import type { FileType } from '@/core/types/api/file'; const FileInfo = ({ compact, file }: { compact?: boolean, file: FileType }) => { const mediaInfo = useMediaInfo(file); + const hash = useMemo(() => getEd2kLink(file), [file]); + const handleCopy = useEventCallback((event: React.MouseEvent) => { + event.stopPropagation(); + copyToClipboard(hash, 'ED2K hash').catch(console.error); + }); + return (
@@ -56,7 +67,12 @@ const FileInfo = ({ compact, file }: { compact?: boolean, file: FileType }) => {
ED2K
- {mediaInfo.Hashes.ED2K ?? ''} +
+ {mediaInfo.Hashes.ED2K ?? ''} +
+ +
+
CRC
diff --git a/src/components/Utilities/Unrecognized/AvDumpFileIcon.tsx b/src/components/Utilities/Unrecognized/AvDumpFileIcon.tsx index 7ede3f8fb..5d20c4c95 100644 --- a/src/components/Utilities/Unrecognized/AvDumpFileIcon.tsx +++ b/src/components/Utilities/Unrecognized/AvDumpFileIcon.tsx @@ -14,6 +14,7 @@ import cx from 'classnames'; import Button from '@/components/Input/Button'; import { useAvdumpFilesMutation } from '@/core/react-query/avdump/mutations'; import { copyToClipboard } from '@/core/util'; +import getEd2kLink from '@/core/utilities/getEd2kLink'; import useEventCallback from '@/hooks/useEventCallback'; import type { RootState } from '@/core/store'; @@ -25,13 +26,7 @@ const AVDumpFileIcon = ({ file, truck = false }: { file: FileType, truck?: boole const fileId = file.ID; const dumpSession = avdumpList.sessions[avdumpList.sessionMap[fileId]]; - const hash = useMemo( - () => - `ed2k://|file|${ - file.Locations[0]?.RelativePath?.split(/[\\/]+/g).pop() ?? '' - }|${file.Size}|${file.Hashes.ED2K}|/`, - [file], - ); + const hash = useMemo(() => getEd2kLink(file), [file]); const { color, path, state, title } = useMemo(() => { if (dumpSession?.status === 'Running') { diff --git a/src/core/utilities/getEd2kLink.ts b/src/core/utilities/getEd2kLink.ts new file mode 100644 index 000000000..072dc0d07 --- /dev/null +++ b/src/core/utilities/getEd2kLink.ts @@ -0,0 +1,6 @@ +import type { FileType } from '@/core/types/api/file'; + +const getEd2kLink = (file: FileType) => + `ed2k://|file|${file.Locations[0]?.RelativePath?.split(/[\\/]+/g).pop() ?? ''}|${file.Size}|${file.Hashes.ED2K}|/`; + +export default getEd2kLink; diff --git a/src/pages/utilities/FileSearch.tsx b/src/pages/utilities/FileSearch.tsx index cd4eca849..d38bbe0dc 100644 --- a/src/pages/utilities/FileSearch.tsx +++ b/src/pages/utilities/FileSearch.tsx @@ -4,6 +4,7 @@ import { Link, useNavigate } from 'react-router-dom'; import { mdiChevronLeft, mdiChevronRight, + mdiClipboardOutline, mdiCloseCircleOutline, mdiDatabaseSearchOutline, mdiDatabaseSyncOutline, @@ -41,6 +42,8 @@ import { invalidateQueries } from '@/core/react-query/queryClient'; import { useSeriesQuery } from '@/core/react-query/series/queries'; import { addFiles } from '@/core/slices/utilities/renamer'; import { FileSortCriteriaEnum } from '@/core/types/api/file'; +import { copyToClipboard } from '@/core/util'; +import getEd2kLink from '@/core/utilities/getEd2kLink'; import useEventCallback from '@/hooks/useEventCallback'; import useFlattenListResult from '@/hooks/useFlattenListResult'; import useMediaInfo from '@/hooks/useMediaInfo'; @@ -169,6 +172,12 @@ const Menu = ( const MediaInfoDetails = React.memo(({ file }: { file: FileType }) => { const mediaInfo = useMediaInfo(file); + const ed2kHash = useMemo(() => getEd2kLink(file), [file]); + + const copyEd2kLink = useEventCallback((event: React.MouseEvent) => { + event.stopPropagation(); + copyToClipboard(ed2kHash, 'ED2K Hash').catch(console.error); + }); return ( <> @@ -204,7 +213,12 @@ const MediaInfoDetails = React.memo(({ file }: { file: FileType }) => {
ED2K
- {mediaInfo.Hashes.ED2K ?? ''} +
+ {mediaInfo.Hashes.ED2K ?? ''} +
+ +
+
diff --git a/src/pages/utilities/UnrecognizedUtilityTabs/UnrecognizedTab.tsx b/src/pages/utilities/UnrecognizedUtilityTabs/UnrecognizedTab.tsx index a9bde1104..982c43543 100644 --- a/src/pages/utilities/UnrecognizedUtilityTabs/UnrecognizedTab.tsx +++ b/src/pages/utilities/UnrecognizedUtilityTabs/UnrecognizedTab.tsx @@ -46,6 +46,7 @@ import { useImportFoldersQuery } from '@/core/react-query/import-folder/queries' import { invalidateQueries } from '@/core/react-query/queryClient'; import { addFiles } from '@/core/slices/utilities/renamer'; import { FileSortCriteriaEnum } from '@/core/types/api/file'; +import getEd2kLink from '@/core/utilities/getEd2kLink'; import useEventCallback from '@/hooks/useEventCallback'; import useFlattenListResult from '@/hooks/useFlattenListResult'; import useRowSelection from '@/hooks/useRowSelection'; @@ -347,10 +348,7 @@ function UnrecognizedTab() { const getED2KLinks = useEventCallback(() => ({ fileIds: selectedRows.map(file => file.ID), links: selectedRows.map( - file => - `ed2k://|file|${ - file.Locations[0]?.RelativePath?.split(/[\\/]+/g).pop() ?? '' - }|${file.Size}|${file.Hashes.ED2K}|/`, + file => getEd2kLink(file), ).toSorted(), }));