Skip to content
Merged
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
69 changes: 69 additions & 0 deletions src/lib/telegram/chat/__tests__/uploadPhotoAttachment.heic.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { readFileSync } from 'node:fs';
import { join } from 'node:path';
import uploadPhotoAttachment from '../uploadPhotoAttachment';

vi.mock('@/lib/supabase/storage/uploadFileToSupabase', () => ({
default: vi.fn(),
}));
vi.mock('@/lib/supabase/storage/uploadJsonToSupabase', () => ({
default: vi.fn(),
}));
vi.mock('../getTelegramFilePath', () => ({ default: vi.fn() }));

import uploadFileToSupabase from '@/lib/supabase/storage/uploadFileToSupabase';
import uploadJsonToSupabase from '@/lib/supabase/storage/uploadJsonToSupabase';
import getTelegramFilePath from '../getTelegramFilePath';

const PHOTO_URL =
'https://supabase.co/storage/v1/object/public/bucket/photo.jpg';
const META_URL =
'https://supabase.co/storage/v1/object/public/bucket/meta.json';

const readHeicFixture = (name: string): Buffer =>
readFileSync(join(__dirname, 'fixtures', name));

const HEIC_DECODE_TIMEOUT_MS = 30_000;

beforeEach(() => {
vi.clearAllMocks();
vi.mocked(getTelegramFilePath).mockResolvedValue('photos/file_1');
vi.mocked(uploadFileToSupabase).mockResolvedValue(PHOTO_URL);
vi.mocked(uploadJsonToSupabase).mockResolvedValue(META_URL);
});

describe('uploadPhotoAttachment HEIC integration', () => {
it(
'uploads HEIC attachments as JPEG',
async () => {
const heicBuffer = readHeicFixture('apple-styled-photo.heic');

const result = await uploadPhotoAttachment(
{
type: 'image',
mimeType: 'image/heic',
fetchData: () => Promise.resolve(heicBuffer),
} as never,
'file-id',
'My HEIC Photo'
);

expect(result.mimeType).toBe('image/jpeg');
expect(uploadFileToSupabase).toHaveBeenCalledOnce();

const [file] = vi.mocked(uploadFileToSupabase).mock.calls[0];
expect(file.type).toBe('image/jpeg');

const uploaded = Buffer.from(await file.arrayBuffer());
expect(uploaded[0]).toBe(0xff);
expect(uploaded[1]).toBe(0xd8);

expect(uploadJsonToSupabase).toHaveBeenCalledWith({
name: 'My HEIC Photo',
image: PHOTO_URL,
content: { mime: 'image/jpeg', uri: PHOTO_URL },
});
},
HEIC_DECODE_TIMEOUT_MS
);
});
13 changes: 11 additions & 2 deletions src/lib/telegram/chat/uploadPhotoAttachment.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import type { Attachment } from 'chat';
import uploadFileToSupabase from '@/lib/supabase/storage/uploadFileToSupabase';
import uploadJsonToSupabase from '@/lib/supabase/storage/uploadJsonToSupabase';
import prepareImageBufferForSharp from '@/lib/media/prepareImageBufferForSharp';
import isHeicBuffer from '@/lib/media/isHeicBuffer';
import getTelegramFilePath from './getTelegramFilePath';
import getMimeTypeFromFilePath from './getMimeTypeFromFilePath';
import toFile from './toFile';
Expand All @@ -16,8 +18,15 @@ const uploadPhotoAttachment = async (
attachment.fetchData(),
getTelegramFilePath(fileId),
]);
const mimeType = attachment.mimeType ?? getMimeTypeFromFilePath(filePath);
const photoFile = toFile(buffer, name, mimeType);
let mimeType = attachment.mimeType ?? getMimeTypeFromFilePath(filePath);
let uploadBuffer = buffer;

if (isHeicBuffer(buffer)) {
uploadBuffer = await prepareImageBufferForSharp(buffer);
mimeType = 'image/jpeg';
}

const photoFile = toFile(uploadBuffer, name, mimeType);
const photoUri = await uploadFileToSupabase(photoFile);

const jsonObject = {
Expand Down
Loading