Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions electron/main/fileReader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,24 @@ export class FileReader {
resolve(content);
} else if (['pdf'].includes(type)) {
resolve(filePath);
} else if (
[
'mp3',
'wav',
'ogg',
'flac',
'aac',
'm4a',
'wma',
'mp4',
'webm',
'ogv',
'mov',
'avi',
'mkv',
].includes(type)
) {
resolve(filePath);
} else if (type === 'csv') {
try {
const htmlContent = await this.parseCsv(filePath);
Expand Down
32 changes: 30 additions & 2 deletions src/components/Folder/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ interface FileInfo {
isRemote?: boolean;
}

const AUDIO_EXTENSIONS = ['mp3', 'wav', 'ogg', 'flac', 'aac', 'm4a', 'wma'];
const VIDEO_EXTENSIONS = ['mp4', 'webm', 'ogv', 'mov', 'avi', 'mkv'];
const MEDIA_EXTENSIONS = [...AUDIO_EXTENSIONS, ...VIDEO_EXTENSIONS];

// FileTree component to render nested file structure
interface FileTreeProps {
node: FileTreeNode;
Expand Down Expand Up @@ -221,8 +225,8 @@ export default function Folder({ data: _data }: { data?: Agent }) {
setLoading(true);
console.log('file', JSON.parse(JSON.stringify(file)));

// For PDF files, use data URL instead of custom protocol
if (file.type === 'pdf') {
// For PDF and audio/video files, use data URL instead of custom protocol
if (['pdf', ...MEDIA_EXTENSIONS].includes(file.type?.toLowerCase())) {
window.ipcRenderer
.invoke('read-file-dataurl', file.path)
.then((dataUrl: string) => {
Expand Down Expand Up @@ -662,6 +666,30 @@ export default function Folder({ data: _data }: { data?: Agent }) {
<div className="flex h-full items-center justify-center">
<ImageLoader selectedFile={selectedFile} />
</div>
) : AUDIO_EXTENSIONS.includes(
selectedFile.type.toLowerCase()
) ? (
<div className="flex h-full items-center justify-center">
<audio
controls
src={selectedFile.content as string}
className="w-full max-w-xl"
>
{t('folder.audio-not-supported')}
</audio>
</div>
) : VIDEO_EXTENSIONS.includes(
selectedFile.type.toLowerCase()
) ? (
<div className="flex h-full items-center justify-center">
<video
controls
src={selectedFile.content as string}
className="max-h-full max-w-full"
>
{t('folder.video-not-supported')}
</video>
</div>
) : (
<pre className="overflow-x-auto whitespace-pre-wrap break-words font-mono text-sm text-text-primary">
{selectedFile.content}
Expand Down
42 changes: 42 additions & 0 deletions test/unit/electron/main/fileReader.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,48 @@ describe('File Operations and Utilities', () => {
});
});

describe('Multimedia File Type Detection', () => {
const audioExtensions = ['mp3', 'wav', 'ogg', 'flac', 'aac', 'm4a', 'wma'];
const videoExtensions = ['mp4', 'webm', 'ogv', 'mov', 'avi', 'mkv'];
const mediaExtensions = [...audioExtensions, ...videoExtensions];

it('should recognize audio file extensions', () => {
audioExtensions.forEach((ext) => {
const filePath = `/path/to/file.${ext}`;
const fileExt = path.extname(filePath).slice(1);
expect(mediaExtensions).toContain(fileExt);
});
});

it('should recognize video file extensions', () => {
videoExtensions.forEach((ext) => {
const filePath = `/path/to/file.${ext}`;
const fileExt = path.extname(filePath).slice(1);
expect(mediaExtensions).toContain(fileExt);
});
});

it('should not treat non-media files as multimedia', () => {
const nonMediaExtensions = ['txt', 'json', 'csv', 'html', 'py', 'js'];
nonMediaExtensions.forEach((ext) => {
const isMedia = mediaExtensions.includes(ext);
expect(isMedia).toBe(false);
});
});

it('should distinguish audio from video extensions', () => {
audioExtensions.forEach((ext) => {
expect(audioExtensions).toContain(ext);
expect(videoExtensions).not.toContain(ext);
});

videoExtensions.forEach((ext) => {
expect(videoExtensions).toContain(ext);
expect(audioExtensions).not.toContain(ext);
});
});
});

describe('File Content Processing', () => {
it('should process text file content', () => {
const content = 'Line 1\nLine 2\nLine 3';
Expand Down