返回 AiToEarn
file.util.ts
1 import * as fs from 'node:fs'
2 import path from 'node:path'
3 import axios, { AxiosResponse } from 'axios'
4 import { v4 as uuidv4 } from 'uuid'
5
6 enum Type {
7 IMAGE = '图片',
8 TXT = '文档',
9 MUSIC = '音乐',
10 VIDEO = '视频',
11 OTHER = '其他',
12 }
13
14 function getResponseHeader(
15 response: AxiosResponse<unknown>,
16 headerName: string,
17 ): string | undefined {
18 const value = response.headers[headerName]
19
20 if (value == null)
21 return undefined
22
23 if (Array.isArray(value))
24 return value.join(', ')
25
26 if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean')
27 return String(value)
28
29 return undefined
30 }
31
32 export function getFileType(extName: string) {
33 const documents = 'txt doc pdf ppt pps xlsx xls docx'
34 const music = 'mp3 wav wma mpa ram ra aac aif m4a'
35 const video = 'avi mpg mpe mpeg asf wmv mov qt rm mp4 flv m4v webm ogv ogg'
36 const image
37 = 'bmp dib pcp dif wmf gif jpg tif eps psd cdr iff tga pcd mpt png jpeg'
38 if (image.includes(extName))
39 return Type.IMAGE
40
41 if (documents.includes(extName))
42 return Type.TXT
43
44 if (music.includes(extName))
45 return Type.MUSIC
46
47 if (video.includes(extName))
48 return Type.VIDEO
49
50 return Type.OTHER
51 }
52
53 export function getName(fileName: string) {
54 if (fileName.includes('.'))
55 return fileName.split('.')[0]
56
57 return fileName
58 }
59
60 export function getExtname(fileName: string) {
61 return path.extname(fileName).replace('.', '')
62 }
63
64 export function getSize(bytes: number, decimals = 2) {
65 if (bytes === 0)
66 return '0 Bytes'
67
68 const k = 1024
69 const dm = decimals < 0 ? 0 : decimals
70 const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
71
72 const i = Math.floor(Math.log(bytes) / Math.log(k))
73
74 return `${Number.parseFloat((bytes / k ** i).toFixed(dm))} ${sizes[i]}`
75 }
76
77 export function saveFile(base64String: string, path: string, fileName: string) {
78 if (!fs.existsSync(path)) {
79 fs.mkdirSync(path, { recursive: true })
80 }
81
82 return new Promise((resolve, reject) => {
83 fs.writeFile(path + fileName, base64String, 'base64', (err) => {
84 if (err) {
85 reject(err)
86 }
87 else {
88 resolve(true)
89 }
90 })
91 })
92 }
93
94 export async function urlToBlob(url: string): Promise<Blob> {
95 const response = await axios.get(url, {
96 responseType: 'arraybuffer',
97 })
98
99 return new Blob([response.data], { type: getResponseHeader(response, 'content-type') })
100 }
101
102 export async function fileUrlToBase64(url: string): Promise<string> {
103 try {
104 const response = await axios.get<ArrayBuffer>(url, {
105 responseType: 'arraybuffer',
106 })
107
108 return Buffer.from(response.data).toString('base64')
109 }
110 catch (error) {
111 throw new Error(`将URL转换为Base64错误: ${error}`)
112 }
113 }
114
115 export async function fileUrlToBlob(url: string): Promise<{ blob: Blob, fileName: string }> {
116 try {
117 const response = await axios.get<ArrayBuffer>(url, {
118 responseType: 'arraybuffer',
119 })
120
121 const contentType
122 = getResponseHeader(response, 'content-type') || 'application/octet-stream'
123 const blob = new Blob([response.data], { type: contentType })
124 return {
125 blob,
126 fileName: url.split('/').pop() || '',
127 }
128 }
129 catch (error) {
130 throw new Error(`将URL转换为Blob错误: ${error}`)
131 }
132 }
133
134 export function getFileTypeFromUrl(url: string, newName = false): string {
135 const urlParts = url.split('.')
136 const extension = urlParts[urlParts.length - 1]
137 return newName ? `${uuidv4()}.${extension}` : extension
138 }
139
140 export async function getFileSizeFromUrl(url: string): Promise<number> {
141 try {
142 const headResponse: AxiosResponse<unknown> = await axios.head(url)
143 const contentLength = Number.parseInt(
144 getResponseHeader(headResponse, 'content-length') || '',
145 10,
146 )
147 return contentLength
148 }
149 catch (error) {
150 throw new Error(`获取文件大小错误: ${error}`)
151 }
152 }
153
154 export async function chunkedDownloadFile(
155 url: string,
156 range: [number, number],
157 ): Promise<Buffer<ArrayBuffer>> {
158 try {
159 const chunk = await axios.get<ArrayBuffer>(url, {
160 responseType: 'arraybuffer',
161 headers: {
162 Range: `bytes=${range[0]}-${range[1]}`,
163 },
164 })
165 return Buffer.from(chunk.data)
166 }
167 catch (error) {
168 throw new Error(`Failed to download file chunk from ${url}: ${error}`)
169 }
170 }
171
172 export async function getRemoteFileSize(url: string): Promise<number> {
173 try {
174 const response = await axios.head(url)
175 if (!response.headers['content-length']) {
176 throw new Error('Content-Length header is missing')
177 }
178 const contentLength = Number.parseInt(
179 getResponseHeader(response, 'content-length') || '',
180 10,
181 )
182 return contentLength
183 }
184 catch (error) {
185 throw new Error(`Failed to get remote file metadata: ${error}, URL: ${url}`)
186 }
187 }
188
189 export async function probeRemoteFile(url: string): Promise<{
190 finalUrl: string
191 contentType?: string
192 contentLength?: string
193 status: number
194 }> {
195 try {
196 const response = await axios.get<ArrayBuffer>(url, {
197 responseType: 'arraybuffer',
198 maxRedirects: 5,
199 headers: {
200 Range: 'bytes=0-0',
201 },
202 validateStatus: () => true,
203 })
204
205 return {
206 finalUrl: response.request?.res?.responseUrl || url,
207 contentType: getResponseHeader(response, 'content-type'),
208 contentLength: getResponseHeader(response, 'content-length'),
209 status: response.status,
210 }
211 }
212 catch (error) {
213 throw new Error(`Failed to probe remote file: ${error}, URL: ${url}`)
214 }
215 }
216
216 lines TYPESCRIPT