From a3c36198112a3090ded21c025f881005d15bf495 Mon Sep 17 00:00:00 2001
From: Feng Kaiyu <loveress01@outlook.com>
Date: Thu, 27 Jun 2024 00:12:30 +0800
Subject: [PATCH] fix(cli): fix broken --album on Windows. (#10626)

Extract folder names via system function to avoid the difference between / and \ on Windows.
---
 cli/src/commands/asset.spec.ts | 19 +++++++++++++++++++
 cli/src/commands/asset.ts      | 11 ++++++-----
 2 files changed, 25 insertions(+), 5 deletions(-)
 create mode 100644 cli/src/commands/asset.spec.ts

diff --git a/cli/src/commands/asset.spec.ts b/cli/src/commands/asset.spec.ts
new file mode 100644
index 0000000000..e42e2ec964
--- /dev/null
+++ b/cli/src/commands/asset.spec.ts
@@ -0,0 +1,19 @@
+import { platform } from 'node:os';
+import { UploadOptionsDto, getAlbumName } from 'src/commands/asset';
+import { describe, expect, it } from 'vitest';
+
+describe('Unit function tests', () => {
+  it('should return a non-undefined value', () => {
+    if (platform() === 'win32') {
+      // This is meaningless for Unix systems.
+      expect(getAlbumName(String.raw`D:\test\Filename.txt`, {} as UploadOptionsDto)).toBe('test');
+    }
+    expect(getAlbumName('D:/parentfolder/test/Filename.txt', {} as UploadOptionsDto)).toBe('test');
+  });
+
+  it('has higher priority to return `albumName` in `options`', () => {
+    expect(getAlbumName('/parentfolder/test/Filename.txt', { albumName: 'example' } as UploadOptionsDto)).toBe(
+      'example',
+    );
+  });
+});
diff --git a/cli/src/commands/asset.ts b/cli/src/commands/asset.ts
index a9b8e0cbee..878ce21e65 100644
--- a/cli/src/commands/asset.ts
+++ b/cli/src/commands/asset.ts
@@ -15,7 +15,6 @@ import { Presets, SingleBar } from 'cli-progress';
 import { chunk } from 'lodash-es';
 import { Stats, createReadStream } from 'node:fs';
 import { stat, unlink } from 'node:fs/promises';
-import os from 'node:os';
 import path, { basename } from 'node:path';
 import { BaseOptions, authenticate, crawl, sha1 } from 'src/utils';
 
@@ -25,7 +24,7 @@ const s = (count: number) => (count === 1 ? '' : 's');
 type AssetBulkUploadCheckResults = Array<AssetBulkUploadCheckResult & { id: string }>;
 type Asset = { id: string; filepath: string };
 
-interface UploadOptionsDto {
+export interface UploadOptionsDto {
   recursive?: boolean;
   ignore?: string;
   dryRun?: boolean;
@@ -346,7 +345,9 @@ const updateAlbums = async (assets: Asset[], options: UploadOptionsDto) => {
   }
 };
 
-const getAlbumName = (filepath: string, options: UploadOptionsDto) => {
-  const folderName = os.platform() === 'win32' ? filepath.split('\\').at(-2) : filepath.split('/').at(-2);
-  return options.albumName ?? folderName;
+// `filepath` valid format:
+// - Windows: `D:\\test\\Filename.txt` or `D:/test/Filename.txt`
+// - Unix: `/test/Filename.txt`
+export const getAlbumName = (filepath: string, options: UploadOptionsDto) => {
+  return options.albumName ?? path.basename(path.dirname(filepath));
 };