From 976d347623ae706f282f72bf866eed8afecb5e47 Mon Sep 17 00:00:00 2001 From: Kiel Hurley Date: Fri, 25 Nov 2022 06:39:27 +1300 Subject: [PATCH] feat(server,web,mobile): Use binary prefixes for data sizes (#1009) --- .../asset_viewer/ui/exif_bottom_sheet.dart | 5 +- mobile/lib/utils/bytes_units.dart | 28 +++++------ .../src/modules/download/download.service.ts | 2 +- .../immich/src/utils/human-readable.util.ts | 46 ++++++++----------- .../server-stats/server-stats-panel.svelte | 4 +- .../asset-viewer/detail-panel.svelte | 33 ++----------- .../shared-components/upload-panel.svelte | 31 ++----------- web/src/lib/utils/byte-units.ts | 16 +++++++ 8 files changed, 64 insertions(+), 101 deletions(-) create mode 100644 web/src/lib/utils/byte-units.ts diff --git a/mobile/lib/modules/asset_viewer/ui/exif_bottom_sheet.dart b/mobile/lib/modules/asset_viewer/ui/exif_bottom_sheet.dart index 483deedc23..23dd1ccb0d 100644 --- a/mobile/lib/modules/asset_viewer/ui/exif_bottom_sheet.dart +++ b/mobile/lib/modules/asset_viewer/ui/exif_bottom_sheet.dart @@ -6,6 +6,7 @@ import 'package:immich_mobile/shared/models/asset.dart'; import 'package:openapi/api.dart'; import 'package:path/path.dart' as p; import 'package:latlong2/latlong.dart'; +import 'package:immich_mobile/utils/bytes_units.dart'; class ExifBottomSheet extends ConsumerWidget { final Asset assetDetail; @@ -162,7 +163,7 @@ class ExifBottomSheet extends ConsumerWidget { ), subtitle: exifInfo.exifImageHeight != null ? Text( - "${exifInfo.exifImageHeight} x ${exifInfo.exifImageWidth} ${exifInfo.fileSizeInByte!}B ", + "${exifInfo.exifImageHeight} x ${exifInfo.exifImageWidth} ${formatBytes(exifInfo.fileSizeInByte!)} ", ) : null, ), @@ -178,7 +179,7 @@ class ExifBottomSheet extends ConsumerWidget { style: const TextStyle(fontWeight: FontWeight.bold), ), subtitle: Text( - "ƒ/${exifInfo.fNumber} 1/${(1 / (exifInfo.exposureTime ?? 1)).toStringAsFixed(0)} ${exifInfo.focalLength}mm ISO${exifInfo.iso} ", + "ƒ/${exifInfo.fNumber} 1/${(1 / (exifInfo.exposureTime ?? 1)).toStringAsFixed(0)} ${exifInfo.focalLength} mm ISO${exifInfo.iso} ", ), ), ], diff --git a/mobile/lib/utils/bytes_units.dart b/mobile/lib/utils/bytes_units.dart index 78e9f17df7..be9ac13dcb 100644 --- a/mobile/lib/utils/bytes_units.dart +++ b/mobile/lib/utils/bytes_units.dart @@ -1,15 +1,17 @@ - String formatBytes(int bytes) { - if (bytes < 1000) { - return "$bytes B"; - } else if (bytes < 1000000) { - final kb = (bytes / 1000).toStringAsFixed(1); - return "$kb kB"; - } else if (bytes < 1000000000) { - final mb = (bytes / 1000000).toStringAsFixed(1); - return "$mb MB"; - } else { - final gb = (bytes / 1000000000).toStringAsFixed(1); - return "$gb GB"; + const units = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB']; + + int magnitude = 0; + double remainder = bytes.toDouble(); + while (remainder >= 1024) { + if (magnitude + 1 < units.length) { + magnitude++; + remainder /= 1024; + } + else { + break; + } } -} \ No newline at end of file + + return "${remainder.toStringAsFixed(magnitude == 0 ? 0 : 1)} ${units[magnitude]}"; +} diff --git a/server/apps/immich/src/modules/download/download.service.ts b/server/apps/immich/src/modules/download/download.service.ts index 191f9addca..0c47cce429 100644 --- a/server/apps/immich/src/modules/download/download.service.ts +++ b/server/apps/immich/src/modules/download/download.service.ts @@ -35,7 +35,7 @@ export class DownloadService { fileCount++; // for easier testing, can be changed before merging. - if (totalSize > HumanReadableSize.GB * 20) { + if (totalSize > HumanReadableSize.GiB * 20) { complete = false; this.logger.log( `Archive size exceeded after ${fileCount} files, capping at ${totalSize} bytes (${asHumanReadable( diff --git a/server/apps/immich/src/utils/human-readable.util.ts b/server/apps/immich/src/utils/human-readable.util.ts index 6c71d05e20..aa9bb04af8 100644 --- a/server/apps/immich/src/utils/human-readable.util.ts +++ b/server/apps/immich/src/utils/human-readable.util.ts @@ -1,31 +1,25 @@ -const KB = 1000; -const MB = KB * 1000; -const GB = MB * 1000; -const TB = GB * 1000; -const PB = TB * 1000; +const KiB = Math.pow(1024, 1); +const MiB = Math.pow(1024, 2); +const GiB = Math.pow(1024, 3); +const TiB = Math.pow(1024, 4); +const PiB = Math.pow(1024, 5); -export const HumanReadableSize = { KB, MB, GB, TB, PB }; +export const HumanReadableSize = { KiB, MiB, GiB, TiB, PiB }; -export function asHumanReadable(bytes: number, precision = 1) { - if (bytes >= PB) { - return `${(bytes / PB).toFixed(precision)}PB`; - } +export function asHumanReadable(bytes: number, precision = 1): string { + const units = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB']; - if (bytes >= TB) { - return `${(bytes / TB).toFixed(precision)}TB`; - } + let magnitude = 0; + let remainder = bytes; + while (remainder >= 1024) { + if (magnitude + 1 < units.length) { + magnitude++; + remainder /= 1024; + } + else { + break; + } + } - if (bytes >= GB) { - return `${(bytes / GB).toFixed(precision)}GB`; - } - - if (bytes >= MB) { - return `${(bytes / MB).toFixed(precision)}MB`; - } - - if (bytes >= KB) { - return `${(bytes / KB).toFixed(precision)}KB`; - } - - return `${bytes}B`; + return `${remainder.toFixed( magnitude == 0 ? 0 : precision )} ${units[magnitude]}`; } diff --git a/web/src/lib/components/admin-page/server-stats/server-stats-panel.svelte b/web/src/lib/components/admin-page/server-stats/server-stats-panel.svelte index bfae8451cc..0ef9184312 100644 --- a/web/src/lib/components/admin-page/server-stats/server-stats-panel.svelte +++ b/web/src/lib/components/admin-page/server-stats/server-stats-panel.svelte @@ -15,8 +15,8 @@ return name; }; - $: spaceUnit = stats.usage.slice(stats.usage.length - 2, stats.usage.length); - $: spaceUsage = stats.usage.slice(0, stats.usage.length - 2); + $: spaceUnit = stats.usage.split(' ')[1]; + $: spaceUsage = stats.usage.split(' ')[0];
diff --git a/web/src/lib/components/asset-viewer/detail-panel.svelte b/web/src/lib/components/asset-viewer/detail-panel.svelte index a254224b5e..c427443392 100644 --- a/web/src/lib/components/asset-viewer/detail-panel.svelte +++ b/web/src/lib/components/asset-viewer/detail-panel.svelte @@ -8,6 +8,7 @@ import { createEventDispatcher, onMount } from 'svelte'; import { browser } from '$app/environment'; import { AssetResponseDto, AlbumResponseDto } from '@api'; + import { getHumanReadableBytes } from '../../utils/byte-units'; type Leaflet = typeof import('leaflet'); type LeafletMap = import('leaflet').Map; @@ -59,32 +60,6 @@ } const dispatch = createEventDispatcher(); - const getHumanReadableString = (sizeInByte: number) => { - const pepibyte = 1.126 * Math.pow(10, 15); - const tebibyte = 1.1 * Math.pow(10, 12); - const gibibyte = 1.074 * Math.pow(10, 9); - const mebibyte = 1.049 * Math.pow(10, 6); - const kibibyte = 1024; - // Pebibyte - if (sizeInByte >= pepibyte) { - // Pe - return `${(sizeInByte / pepibyte).toFixed(1)}PB`; - } else if (tebibyte <= sizeInByte && sizeInByte < pepibyte) { - // Te - return `${(sizeInByte / tebibyte).toFixed(1)}TB`; - } else if (gibibyte <= sizeInByte && sizeInByte < tebibyte) { - // Gi - return `${(sizeInByte / gibibyte).toFixed(1)}GB`; - } else if (mebibyte <= sizeInByte && sizeInByte < gibibyte) { - // Mega - return `${(sizeInByte / mebibyte).toFixed(1)}MB`; - } else if (kibibyte <= sizeInByte && sizeInByte < mebibyte) { - // Kibi - return `${(sizeInByte / kibibyte).toFixed(1)}KB`; - } else { - return `${sizeInByte}B`; - } - }; const getMegapixel = (width: number, height: number): number | undefined => { const megapixel = Math.round((height * width) / 1_000_000); @@ -143,13 +118,13 @@ {#if asset.exifInfo.exifImageHeight && asset.exifInfo.exifImageWidth} {#if getMegapixel(asset.exifInfo.exifImageHeight, asset.exifInfo.exifImageWidth)}

- {getMegapixel(asset.exifInfo.exifImageHeight, asset.exifInfo.exifImageWidth)}MP + {getMegapixel(asset.exifInfo.exifImageHeight, asset.exifInfo.exifImageWidth)} MP

{/if}

{asset.exifInfo.exifImageHeight} x {asset.exifInfo.exifImageWidth}

{/if} -

{getHumanReadableString(asset.exifInfo.fileSizeInByte)}

+

{getHumanReadableBytes(asset.exifInfo.fileSizeInByte)}

@@ -162,7 +137,7 @@

{asset.exifInfo.make || ''} {asset.exifInfo.model || ''}

-

{`f/${asset.exifInfo.fNumber}` || ''}

+

{`ƒ/${asset.exifInfo.fNumber}` || ''}

{#if asset.exifInfo.exposureTime}

{`1/${Math.floor(1 / asset.exifInfo.exposureTime)}`}

diff --git a/web/src/lib/components/shared-components/upload-panel.svelte b/web/src/lib/components/shared-components/upload-panel.svelte index f33df973d4..0901cc008c 100644 --- a/web/src/lib/components/shared-components/upload-panel.svelte +++ b/web/src/lib/components/shared-components/upload-panel.svelte @@ -6,6 +6,8 @@ import WindowMinimize from 'svelte-material-icons/WindowMinimize.svelte'; import type { UploadAsset } from '$lib/models/upload-asset'; import { notificationController, NotificationType } from './notification/notification'; + import { getHumanReadableBytes } from '../../utils/byte-units'; + let showDetail = true; let uploadLength = 0; @@ -30,33 +32,6 @@ } }; - function getSizeInHumanReadableFormat(sizeInByte: number) { - const pepibyte = 1.126 * Math.pow(10, 15); - const tebibyte = 1.1 * Math.pow(10, 12); - const gibibyte = 1.074 * Math.pow(10, 9); - const mebibyte = 1.049 * Math.pow(10, 6); - const kibibyte = 1024; - // Pebibyte - if (sizeInByte >= pepibyte) { - // Pe - return `${(sizeInByte / pepibyte).toFixed(1)}PB`; - } else if (tebibyte <= sizeInByte && sizeInByte < pepibyte) { - // Te - return `${(sizeInByte / tebibyte).toFixed(1)}TB`; - } else if (gibibyte <= sizeInByte && sizeInByte < tebibyte) { - // Gi - return `${(sizeInByte / gibibyte).toFixed(1)}GB`; - } else if (mebibyte <= sizeInByte && sizeInByte < gibibyte) { - // Mega - return `${(sizeInByte / mebibyte).toFixed(1)}MB`; - } else if (kibibyte <= sizeInByte && sizeInByte < mebibyte) { - // Kibi - return `${(sizeInByte / kibibyte).toFixed(1)}KB`; - } else { - return `${sizeInByte}B`; - } - } - // Reactive action to get thumbnail image of upload asset whenever there is a new one added to the list $: { if ($uploadAssetsStore.length != uploadLength) { @@ -140,7 +115,7 @@ diff --git a/web/src/lib/utils/byte-units.ts b/web/src/lib/utils/byte-units.ts new file mode 100644 index 0000000000..f8fa139fbe --- /dev/null +++ b/web/src/lib/utils/byte-units.ts @@ -0,0 +1,16 @@ +export function getHumanReadableBytes(bytes: number): string { + const units = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB']; + + let magnitude = 0; + let remainder = bytes; + while (remainder >= 1024) { + if (magnitude + 1 < units.length) { + magnitude++; + remainder /= 1024; + } else { + break; + } + } + + return `${remainder.toFixed(magnitude == 0 ? 0 : 1)} ${units[magnitude]}`; +}