fix(core): automatically add relevant file extension
This commit is contained in:
parent
3580575b82
commit
32e29715ad
3 changed files with 98 additions and 60 deletions
|
@ -5,7 +5,7 @@ import { MtArgumentError } from '../../../types/errors.js'
|
||||||
import { randomLong } from '../../../utils/long-utils.js'
|
import { randomLong } from '../../../utils/long-utils.js'
|
||||||
import { ITelegramClient } from '../../client.types.js'
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
import { UploadedFile, UploadFileLike } from '../../types/index.js'
|
import { UploadedFile, UploadFileLike } from '../../types/index.js'
|
||||||
import { guessFileMime } from '../../utils/file-type.js'
|
import { guessFileMime, MIME_TO_EXTENSION } from '../../utils/file-type.js'
|
||||||
import { determinePartSize, isProbablyPlainText } from '../../utils/file-utils.js'
|
import { determinePartSize, isProbablyPlainText } from '../../utils/file-utils.js'
|
||||||
import { bufferToStream, createChunkedReader, streamToBuffer } from '../../utils/stream-utils.js'
|
import { bufferToStream, createChunkedReader, streamToBuffer } from '../../utils/stream-utils.js'
|
||||||
|
|
||||||
|
@ -105,7 +105,7 @@ export async function uploadFile(
|
||||||
// normalize params
|
// normalize params
|
||||||
let file = params.file
|
let file = params.file
|
||||||
let fileSize = -1 // unknown
|
let fileSize = -1 // unknown
|
||||||
let fileName = DEFAULT_FILE_NAME
|
let fileName = params.fileName
|
||||||
let fileMime = params.fileMime
|
let fileMime = params.fileMime
|
||||||
|
|
||||||
const platform = getPlatform()
|
const platform = getPlatform()
|
||||||
|
@ -178,9 +178,6 @@ export async function uploadFile(
|
||||||
throw new MtArgumentError('Could not convert input `file` to stream!')
|
throw new MtArgumentError('Could not convert input `file` to stream!')
|
||||||
}
|
}
|
||||||
|
|
||||||
// override file name and mime (if any)
|
|
||||||
if (params.fileName) fileName = params.fileName
|
|
||||||
|
|
||||||
// set file size if not automatically inferred
|
// set file size if not automatically inferred
|
||||||
if (fileSize === -1 && params.fileSize) fileSize = params.fileSize
|
if (fileSize === -1 && params.fileSize) fileSize = params.fileSize
|
||||||
|
|
||||||
|
@ -229,8 +226,6 @@ export async function uploadFile(
|
||||||
connectionPoolSize,
|
connectionPoolSize,
|
||||||
)
|
)
|
||||||
|
|
||||||
// why is the file id generated by the client?
|
|
||||||
// isn't the server supposed to generate it and handle collisions?
|
|
||||||
const fileId = randomLong()
|
const fileId = randomLong()
|
||||||
const stream = file
|
const stream = file
|
||||||
|
|
||||||
|
@ -309,6 +304,13 @@ export async function uploadFile(
|
||||||
|
|
||||||
await Promise.all(Array.from({ length: poolSize }, uploadNextPart))
|
await Promise.all(Array.from({ length: poolSize }, uploadNextPart))
|
||||||
|
|
||||||
|
if (fileName === undefined) {
|
||||||
|
// infer file extension from mime type. for some media types,
|
||||||
|
// telegram requires us to specify the file extension
|
||||||
|
const ext = MIME_TO_EXTENSION[fileMime!]
|
||||||
|
fileName = ext ? `${DEFAULT_FILE_NAME}.${ext}` : DEFAULT_FILE_NAME
|
||||||
|
}
|
||||||
|
|
||||||
let inputFile: tl.TypeInputFile
|
let inputFile: tl.TypeInputFile
|
||||||
|
|
||||||
if (isBig) {
|
if (isBig) {
|
||||||
|
|
|
@ -1,66 +1,67 @@
|
||||||
import { describe, expect, it } from 'vitest'
|
import { describe, expect, it } from 'vitest'
|
||||||
|
|
||||||
import { getPlatform } from '../../platform.js'
|
import { getPlatform } from '../../platform.js'
|
||||||
import { guessFileMime } from './file-type.js'
|
import { guessFileMime, MIME_TO_EXTENSION } from './file-type.js'
|
||||||
|
|
||||||
const p = getPlatform()
|
const p = getPlatform()
|
||||||
|
|
||||||
describe('guessFileMime', () => {
|
describe('guessFileMime', () => {
|
||||||
it.each([
|
it.each([
|
||||||
['424d', 'image/bmp'],
|
['424d', 'image/bmp', 'bmp'],
|
||||||
['4d5a', 'application/x-msdownload'],
|
['4d5a', 'application/x-msdownload', 'exe'],
|
||||||
['1f9d', 'application/x-compress'],
|
['1f9d', 'application/x-compress', 'z'],
|
||||||
['1fa0', 'application/x-compress'],
|
['1fa0', 'application/x-compress', 'z'],
|
||||||
['1f8b', 'application/gzip'],
|
['1f8b', 'application/gzip', 'gz'],
|
||||||
['425a68', 'application/x-bzip2'],
|
['425a68', 'application/x-bzip2', 'bz2'],
|
||||||
['494433', 'audio/mpeg'],
|
['494433', 'audio/mpeg', 'mp3'],
|
||||||
['fffb', 'audio/mpeg'],
|
['fffb', 'audio/mpeg', 'mp3'],
|
||||||
['fff3', 'audio/mpeg'],
|
['fff3', 'audio/mpeg', 'mp3'],
|
||||||
['fff2', 'audio/mpeg'],
|
['fff2', 'audio/mpeg', 'mp3'],
|
||||||
['504b0304', 'application/zip'],
|
['504b0304', 'application/zip', 'zip'],
|
||||||
['38425053', 'image/vnd.adobe.photoshop'],
|
['38425053', 'image/vnd.adobe.photoshop', 'psd'],
|
||||||
['7f454c46', 'application/x-elf'],
|
['7f454c46', 'application/x-elf', undefined],
|
||||||
['feedfacf', 'application/x-mach-binary'],
|
['feedfacf', 'application/x-mach-binary', undefined],
|
||||||
['28b52ffd', 'application/zstd'],
|
['28b52ffd', 'application/zstd', 'zst'],
|
||||||
['664c6143', 'audio/x-flac'],
|
['664c6143', 'audio/x-flac', 'flac'],
|
||||||
['ffd8ffdb', 'image/jpeg'],
|
['ffd8ffdb', 'image/jpeg', 'jpg'],
|
||||||
['ffd8ffe0', 'image/jpeg'],
|
['ffd8ffe0', 'image/jpeg', 'jpg'],
|
||||||
['ffd8ffee', 'image/jpeg'],
|
['ffd8ffee', 'image/jpeg', 'jpg'],
|
||||||
['ffd8ffe1', 'image/jpeg'],
|
['ffd8ffe1', 'image/jpeg', 'jpg'],
|
||||||
['4f676753', 'application/ogg'],
|
['4f676753', 'application/ogg', 'ogg'],
|
||||||
['4f6767530000000000000000000000000000000000000000000000004f70757348656164', 'audio/ogg'],
|
['4f6767530000000000000000000000000000000000000000000000004f70757348656164', 'audio/ogg', 'ogg'],
|
||||||
['4f67675300000000000000000000000000000000000000000000000001766964656f', 'video/ogg'],
|
['4f67675300000000000000000000000000000000000000000000000001766964656f', 'video/ogg', 'ogv'],
|
||||||
['4f6767530000000000000000000000000000000000000000000000007f464c4143', 'audio/ogg'],
|
['4f6767530000000000000000000000000000000000000000000000007f464c4143', 'audio/ogg', 'ogg'],
|
||||||
['4f67675300000000000000000000000000000000000000000000000001766f72626973', 'audio/ogg'],
|
['4f67675300000000000000000000000000000000000000000000000001766f72626973', 'audio/ogg', 'ogg'],
|
||||||
['255044462d', 'application/pdf'],
|
['255044462d', 'application/pdf', 'pdf'],
|
||||||
['474946383761', 'image/gif'],
|
['474946383761', 'image/gif', 'gif'],
|
||||||
['474946383961', 'image/gif'],
|
['474946383961', 'image/gif', 'gif'],
|
||||||
['377abcaf271c', 'application/x-7z-compressed'],
|
['377abcaf271c', 'application/x-7z-compressed', '7z'],
|
||||||
['89504e470d0a1a0a', 'image/png'],
|
['89504e470d0a1a0a', 'image/png', 'png'],
|
||||||
['526172211a0700', 'application/x-rar-compressed'],
|
['526172211a0700', 'application/x-rar-compressed', 'rar'],
|
||||||
['526172211a0701', 'application/x-rar-compressed'],
|
['526172211a0701', 'application/x-rar-compressed', 'rar'],
|
||||||
['000000006674797061766966', 'image/avif'],
|
['000000006674797061766966', 'image/avif', 'avif'],
|
||||||
['000000006674797061766973', 'image/avif'],
|
['000000006674797061766973', 'image/avif', 'avif'],
|
||||||
['00000000667479706d696631', 'image/heif'],
|
['00000000667479706d696631', 'image/heif', 'heif'],
|
||||||
['000000006674797068656963', 'image/heic'],
|
['000000006674797068656963', 'image/heic', 'heic'],
|
||||||
['000000006674797068656978', 'image/heic'],
|
['000000006674797068656978', 'image/heic', 'heic'],
|
||||||
['000000006674797068657663', 'image/heic-sequence'],
|
['000000006674797068657663', 'image/heic-sequence', 'heic'],
|
||||||
['000000006674797068657678', 'image/heic-sequence'],
|
['000000006674797068657678', 'image/heic-sequence', 'heic'],
|
||||||
['000000006674797071740000', 'video/quicktime'],
|
['000000006674797071740000', 'video/quicktime', 'mov'],
|
||||||
['00000000667479704d345600', 'video/x-m4v'],
|
['00000000667479704d345600', 'video/x-m4v', 'm4v'],
|
||||||
['00000000667479704d345648', 'video/x-m4v'],
|
['00000000667479704d345648', 'video/x-m4v', 'm4v'],
|
||||||
['00000000667479704d345650', 'video/x-m4v'],
|
['00000000667479704d345650', 'video/x-m4v', 'm4v'],
|
||||||
['00000000667479704d345000', 'video/mp4'],
|
['00000000667479704d345000', 'video/mp4', 'mp4'],
|
||||||
['00000000667479704d344100', 'audio/x-m4a'],
|
['00000000667479704d344100', 'audio/x-m4a', 'm4a'],
|
||||||
['00000000667479704d344200', 'audio/mp4'],
|
['00000000667479704d344200', 'audio/mp4', 'm4a'],
|
||||||
['000000006674797046344100', 'audio/mp4'],
|
['000000006674797046344100', 'audio/mp4', 'm4a'],
|
||||||
['000000006674797046344200', 'audio/mp4'],
|
['000000006674797046344200', 'audio/mp4', 'm4a'],
|
||||||
['000000006674797063727800', 'image/x-canon-cr3'],
|
['000000006674797063727800', 'image/x-canon-cr3', 'cr3'],
|
||||||
['000000006674797033673200', 'video/3gpp2'],
|
['000000006674797033673200', 'video/3gpp2', '3g2'],
|
||||||
['000000006674797033670000', 'video/3gpp'],
|
['000000006674797033670000', 'video/3gpp', '3gp'],
|
||||||
])('should detect %s as %s', (header, mime) => {
|
])('should detect %s as %s with %s extension', (header, mime, ext) => {
|
||||||
header += '00'.repeat(16)
|
header += '00'.repeat(16)
|
||||||
|
|
||||||
expect(guessFileMime(p.hexDecode(header))).toEqual(mime)
|
expect(guessFileMime(p.hexDecode(header))).toEqual(mime)
|
||||||
|
expect(MIME_TO_EXTENSION[mime]).toEqual(ext)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -128,3 +128,38 @@ export function guessFileMime(chunk: Uint8Array): string | null {
|
||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const MIME_TO_EXTENSION: Record<string, string | undefined> = {
|
||||||
|
'image/bmp': 'bmp',
|
||||||
|
'application/x-msdownload': 'exe',
|
||||||
|
'application/x-compress': 'z',
|
||||||
|
'application/gzip': 'gz',
|
||||||
|
'application/x-bzip2': 'bz2',
|
||||||
|
'audio/mpeg': 'mp3',
|
||||||
|
'application/zip': 'zip',
|
||||||
|
'image/vnd.adobe.photoshop': 'psd',
|
||||||
|
'application/zstd': 'zst',
|
||||||
|
'audio/x-flac': 'flac',
|
||||||
|
'image/jpeg': 'jpg',
|
||||||
|
'audio/ogg': 'ogg',
|
||||||
|
'video/ogg': 'ogv',
|
||||||
|
'application/ogg': 'ogg',
|
||||||
|
'application/pdf': 'pdf',
|
||||||
|
'image/gif': 'gif',
|
||||||
|
'application/x-7z-compressed': '7z',
|
||||||
|
'image/png': 'png',
|
||||||
|
'application/x-rar-compressed': 'rar',
|
||||||
|
'image/avif': 'avif',
|
||||||
|
'image/heif': 'heif',
|
||||||
|
'image/heif-sequence': 'heif',
|
||||||
|
'image/heic': 'heic',
|
||||||
|
'image/heic-sequence': 'heic',
|
||||||
|
'video/quicktime': 'mov',
|
||||||
|
'video/x-m4v': 'm4v',
|
||||||
|
'audio/x-m4a': 'm4a',
|
||||||
|
'audio/mp4': 'm4a',
|
||||||
|
'image/x-canon-cr3': 'cr3',
|
||||||
|
'video/3gpp2': '3g2',
|
||||||
|
'video/3gpp': '3gp',
|
||||||
|
'video/mp4': 'mp4',
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue