@yimingliao/cms 0.0.7 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/base-DbGnfZr6.d.ts +340 -0
- package/dist/chunk-KEQXXUK2.js +207 -0
- package/dist/index.d.ts +8 -902
- package/dist/index.js +1 -1421
- package/dist/server/index.d.ts +566 -0
- package/dist/server/index.js +1242 -0
- package/package.json +1 -1
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
type SingleItem = {
|
|
2
|
+
id: string;
|
|
3
|
+
} | null;
|
|
4
|
+
type MultiItems = {
|
|
5
|
+
id: string;
|
|
6
|
+
}[];
|
|
7
|
+
|
|
8
|
+
type BaseTranslation<T extends string = string> = {
|
|
9
|
+
locale: T;
|
|
10
|
+
};
|
|
11
|
+
type Translation<T extends string = string> = BaseTranslation<T> & {
|
|
12
|
+
[k: string]: unknown;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
declare const ADMIN_ROLES: {
|
|
16
|
+
SUPER_ADMIN: "SUPER_ADMIN";
|
|
17
|
+
ADMIN: "ADMIN";
|
|
18
|
+
EDITOR: "EDITOR";
|
|
19
|
+
};
|
|
20
|
+
type AdminRole = (typeof ADMIN_ROLES)[keyof typeof ADMIN_ROLES];
|
|
21
|
+
|
|
22
|
+
interface Admin {
|
|
23
|
+
id: string;
|
|
24
|
+
email: string;
|
|
25
|
+
role: AdminRole;
|
|
26
|
+
passwordHash: string;
|
|
27
|
+
socialLinks: string[];
|
|
28
|
+
avatarImageId: string | null;
|
|
29
|
+
createdAt: Date;
|
|
30
|
+
updatedAt: Date;
|
|
31
|
+
emailVerifiedAt: Date | null;
|
|
32
|
+
}
|
|
33
|
+
type AdminSafe = Omit<Admin, "passwordHash">;
|
|
34
|
+
|
|
35
|
+
interface AdminTranslation extends Translation {
|
|
36
|
+
id: string;
|
|
37
|
+
locale: string;
|
|
38
|
+
adminId: string;
|
|
39
|
+
name: string | null;
|
|
40
|
+
authorName: string | null;
|
|
41
|
+
description: string | null;
|
|
42
|
+
jobTitle: string | null;
|
|
43
|
+
url: string | null;
|
|
44
|
+
worksFor: string | null;
|
|
45
|
+
knowsAbout: string[];
|
|
46
|
+
homeLocation: string | null;
|
|
47
|
+
nationality: string | null;
|
|
48
|
+
createdAt: Date;
|
|
49
|
+
updatedAt: Date;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
interface DeviceInfo {
|
|
53
|
+
deviceType: "mobile" | "tablet" | "console" | "smarttv" | "wearable" | "xr" | "embedded";
|
|
54
|
+
platform: string;
|
|
55
|
+
timezone?: string;
|
|
56
|
+
language?: string;
|
|
57
|
+
screenResolution?: {
|
|
58
|
+
width: number;
|
|
59
|
+
height: number;
|
|
60
|
+
};
|
|
61
|
+
browser?: string;
|
|
62
|
+
browserVersion?: string;
|
|
63
|
+
userAgent?: string;
|
|
64
|
+
[key: string]: unknown;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
interface AdminRefreshToken {
|
|
68
|
+
id: string;
|
|
69
|
+
tokenHash: string;
|
|
70
|
+
email: string;
|
|
71
|
+
ip: string;
|
|
72
|
+
deviceInfo: DeviceInfo | null;
|
|
73
|
+
adminId: string;
|
|
74
|
+
createdAt: Date;
|
|
75
|
+
expiresAt: Date;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
declare const FILE_TYPES: {
|
|
79
|
+
IMAGE: "IMAGE";
|
|
80
|
+
AUDIO: "AUDIO";
|
|
81
|
+
VIDEO: "VIDEO";
|
|
82
|
+
DOCUMENT: "DOCUMENT";
|
|
83
|
+
ARCHIVE: "ARCHIVE";
|
|
84
|
+
OTHER: "OTHER";
|
|
85
|
+
};
|
|
86
|
+
type FileType = (typeof FILE_TYPES)[keyof typeof FILE_TYPES];
|
|
87
|
+
|
|
88
|
+
interface File {
|
|
89
|
+
id: string;
|
|
90
|
+
key: string;
|
|
91
|
+
checksum: string;
|
|
92
|
+
width: number | null;
|
|
93
|
+
height: number | null;
|
|
94
|
+
duration: number | null;
|
|
95
|
+
originalName: string;
|
|
96
|
+
size: number;
|
|
97
|
+
extension: string;
|
|
98
|
+
mimeType: string;
|
|
99
|
+
type: FileType;
|
|
100
|
+
isLocked: boolean;
|
|
101
|
+
folderId: string | null;
|
|
102
|
+
createdAt: Date;
|
|
103
|
+
updatedAt: Date;
|
|
104
|
+
deletedAt: Date | null;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
interface FileTranslation extends Translation {
|
|
108
|
+
id: string;
|
|
109
|
+
locale: string;
|
|
110
|
+
name: string | null;
|
|
111
|
+
alt: string | null;
|
|
112
|
+
fileId: string;
|
|
113
|
+
createdAt: Date;
|
|
114
|
+
updatedAt: Date;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
interface Folder {
|
|
118
|
+
id: string;
|
|
119
|
+
name: string;
|
|
120
|
+
key: string;
|
|
121
|
+
isLocked: boolean;
|
|
122
|
+
parentFolderId: string | null;
|
|
123
|
+
createdAt: Date;
|
|
124
|
+
updatedAt: Date;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
type FolderFull = Folder & {
|
|
128
|
+
parentFolder: (Folder & {
|
|
129
|
+
subFolders: Folder[];
|
|
130
|
+
files: File[];
|
|
131
|
+
}) | null;
|
|
132
|
+
subFolders: Folder[];
|
|
133
|
+
files: File[];
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
declare const POST_TYPES: {
|
|
137
|
+
TOPIC: "TOPIC";
|
|
138
|
+
CATEGORY: "CATEGORY";
|
|
139
|
+
POST: "POST";
|
|
140
|
+
TAG: "TAG";
|
|
141
|
+
PAGE: "PAGE";
|
|
142
|
+
};
|
|
143
|
+
type PostType = (typeof POST_TYPES)[keyof typeof POST_TYPES];
|
|
144
|
+
interface ExternalLink {
|
|
145
|
+
name: string;
|
|
146
|
+
href: string;
|
|
147
|
+
}
|
|
148
|
+
interface Faq {
|
|
149
|
+
question: string;
|
|
150
|
+
answer: string;
|
|
151
|
+
}
|
|
152
|
+
interface TocItem {
|
|
153
|
+
text: string;
|
|
154
|
+
id: string;
|
|
155
|
+
level: 2 | 3 | 4 | 5 | 6;
|
|
156
|
+
children?: TocItem[];
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
interface Post {
|
|
160
|
+
id: string;
|
|
161
|
+
type: PostType;
|
|
162
|
+
isLocked: boolean;
|
|
163
|
+
isActive: boolean;
|
|
164
|
+
isIndexActive: boolean;
|
|
165
|
+
index: number | null;
|
|
166
|
+
isSlugActive: boolean;
|
|
167
|
+
slug: string;
|
|
168
|
+
isFeatured: boolean;
|
|
169
|
+
isShownOnHome: boolean;
|
|
170
|
+
authorId: string | null;
|
|
171
|
+
topicId: string | null;
|
|
172
|
+
coverImageId: string | null;
|
|
173
|
+
createdAt: Date;
|
|
174
|
+
updatedAt: Date;
|
|
175
|
+
deletedAt: Date | null;
|
|
176
|
+
state1: boolean;
|
|
177
|
+
state2: boolean;
|
|
178
|
+
state3: boolean;
|
|
179
|
+
state4: boolean;
|
|
180
|
+
state5: boolean;
|
|
181
|
+
state6: boolean;
|
|
182
|
+
state7: boolean;
|
|
183
|
+
state8: boolean;
|
|
184
|
+
state9: boolean;
|
|
185
|
+
state10: boolean;
|
|
186
|
+
image1Id: string | null;
|
|
187
|
+
image2Id: string | null;
|
|
188
|
+
image3Id: string | null;
|
|
189
|
+
image4Id: string | null;
|
|
190
|
+
text1: string | null;
|
|
191
|
+
text2: string | null;
|
|
192
|
+
text3: string | null;
|
|
193
|
+
text4: string | null;
|
|
194
|
+
text5: string | null;
|
|
195
|
+
text6: string | null;
|
|
196
|
+
text7: string | null;
|
|
197
|
+
text8: string | null;
|
|
198
|
+
text9: string | null;
|
|
199
|
+
text10: string | null;
|
|
200
|
+
data1: any[];
|
|
201
|
+
data2: any[];
|
|
202
|
+
data3: any[];
|
|
203
|
+
data4: any[];
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
interface PostTranslation extends Translation {
|
|
207
|
+
id: string;
|
|
208
|
+
locale: string;
|
|
209
|
+
title: string | null;
|
|
210
|
+
subtitle: string | null;
|
|
211
|
+
summary: string | null;
|
|
212
|
+
description: string | null;
|
|
213
|
+
content: string | null;
|
|
214
|
+
externalLinks: ExternalLink[];
|
|
215
|
+
faq: Faq[];
|
|
216
|
+
toc: TocItem[];
|
|
217
|
+
readTime: number | null;
|
|
218
|
+
wordCount: number;
|
|
219
|
+
postId: string;
|
|
220
|
+
createdAt: Date;
|
|
221
|
+
updatedAt: Date;
|
|
222
|
+
text1: string | null;
|
|
223
|
+
text2: string | null;
|
|
224
|
+
text3: string | null;
|
|
225
|
+
text4: string | null;
|
|
226
|
+
text5: string | null;
|
|
227
|
+
text6: string | null;
|
|
228
|
+
text7: string | null;
|
|
229
|
+
text8: string | null;
|
|
230
|
+
text9: string | null;
|
|
231
|
+
text10: string | null;
|
|
232
|
+
data1: any[];
|
|
233
|
+
data2: any[];
|
|
234
|
+
data3: any[];
|
|
235
|
+
data4: any[];
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
type PostListCard = Post & {
|
|
239
|
+
topic: (Post & {
|
|
240
|
+
translations: PostTranslation[];
|
|
241
|
+
}) | null;
|
|
242
|
+
postsInTopic: Post[];
|
|
243
|
+
children: Post[];
|
|
244
|
+
taggedPosts: Post[];
|
|
245
|
+
coverImage: File | null;
|
|
246
|
+
translations: PostTranslation[];
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
type PostFull = Post & {
|
|
250
|
+
author: AdminCard | null;
|
|
251
|
+
topic: PostListCard | null;
|
|
252
|
+
postsInTopic: PostListCard[];
|
|
253
|
+
parents: PostListCard[];
|
|
254
|
+
children: PostListCard[];
|
|
255
|
+
tags: PostListCard[];
|
|
256
|
+
taggedPosts: PostListCard[];
|
|
257
|
+
relatedPosts: PostListCard[];
|
|
258
|
+
referencingPosts: PostListCard[];
|
|
259
|
+
coverImage: FileCard | null;
|
|
260
|
+
images1: FileCard[];
|
|
261
|
+
images2: FileCard[];
|
|
262
|
+
image1: FileCard | null;
|
|
263
|
+
image2: FileCard | null;
|
|
264
|
+
image3: FileCard | null;
|
|
265
|
+
image4: FileCard | null;
|
|
266
|
+
translations: PostTranslation[];
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
type FileFull = File & {
|
|
270
|
+
folder: Folder | null;
|
|
271
|
+
adminAsAvatarImage: Admin[];
|
|
272
|
+
postsAsCoverImage: Post[];
|
|
273
|
+
postsAsContentImage: Post[];
|
|
274
|
+
postsAsImages1: Post[];
|
|
275
|
+
postsAsImages2: Post[];
|
|
276
|
+
postsAsImage1: Post[];
|
|
277
|
+
postsAsImage2: Post[];
|
|
278
|
+
postsAsImage3: Post[];
|
|
279
|
+
postsAsImage4: Post[];
|
|
280
|
+
translations: FileTranslation[];
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
type FileCard = File & {
|
|
284
|
+
translations: FileTranslation[];
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
type AdminFull = AdminSafe & {
|
|
288
|
+
adminRefreshTokens: AdminRefreshToken[];
|
|
289
|
+
avatarImage: (File & {
|
|
290
|
+
translations: FileTranslation[];
|
|
291
|
+
}) | null;
|
|
292
|
+
posts: Post[];
|
|
293
|
+
translations: AdminTranslation[];
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
type AdminCard = AdminSafe & {
|
|
297
|
+
translations: AdminTranslation[];
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
interface Alternate {
|
|
301
|
+
hreflang: string;
|
|
302
|
+
href: string | null;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
interface SeoMetadata {
|
|
306
|
+
id: string;
|
|
307
|
+
locale: string;
|
|
308
|
+
title: string | null;
|
|
309
|
+
description: string | null;
|
|
310
|
+
author: string | null;
|
|
311
|
+
canonical: string | null;
|
|
312
|
+
alternate: Alternate[];
|
|
313
|
+
robots: string | null;
|
|
314
|
+
ogTitle: string | null;
|
|
315
|
+
ogDescription: string | null;
|
|
316
|
+
ogUrl: string | null;
|
|
317
|
+
ogType: string | null;
|
|
318
|
+
ogSiteName: string | null;
|
|
319
|
+
ogImage: string | null;
|
|
320
|
+
ogImageAlt: string | null;
|
|
321
|
+
ogImageType: string | null;
|
|
322
|
+
ogImageWidth: number | null;
|
|
323
|
+
ogImageHeight: number | null;
|
|
324
|
+
ogLocale: string | null;
|
|
325
|
+
ogLocaleAlternate: string[];
|
|
326
|
+
ogArticlePublishedTime: Date | null;
|
|
327
|
+
ogArticleModifiedTime: Date | null;
|
|
328
|
+
ogArticleAuthor: string | null;
|
|
329
|
+
ogArticleSection: string | null;
|
|
330
|
+
ogArticleTag: string[];
|
|
331
|
+
twitterCard: string | null;
|
|
332
|
+
twitterSite: string | null;
|
|
333
|
+
twitterCreator: string | null;
|
|
334
|
+
jsonLd: object[];
|
|
335
|
+
postId: string;
|
|
336
|
+
createdAt: Date;
|
|
337
|
+
updatedAt: Date;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
export { ADMIN_ROLES as A, type BaseTranslation as B, type DeviceInfo as D, type ExternalLink as E, type FolderFull as F, type MultiItems as M, POST_TYPES as P, type SeoMetadata as S, type TocItem as T, type Admin as a, type AdminCard as b, type AdminFull as c, type AdminRefreshToken as d, type AdminRole as e, type AdminSafe as f, type AdminTranslation as g, type Alternate as h, FILE_TYPES as i, type Faq as j, type File as k, type FileCard as l, type FileFull as m, type FileTranslation as n, type FileType as o, type Folder as p, type Post as q, type PostFull as r, type PostListCard as s, type PostTranslation as t, type PostType as u, type SingleItem as v, type Translation as w };
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { extension, lookup } from 'mime-types';
|
|
2
|
+
|
|
3
|
+
// src/domain/resources/admin/props.ts
|
|
4
|
+
var ADMIN_ROLES = {
|
|
5
|
+
SUPER_ADMIN: "SUPER_ADMIN",
|
|
6
|
+
ADMIN: "ADMIN",
|
|
7
|
+
EDITOR: "EDITOR"
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
// src/domain/resources/file/props.ts
|
|
11
|
+
var FILE_TYPES = {
|
|
12
|
+
IMAGE: "IMAGE",
|
|
13
|
+
AUDIO: "AUDIO",
|
|
14
|
+
VIDEO: "VIDEO",
|
|
15
|
+
DOCUMENT: "DOCUMENT",
|
|
16
|
+
ARCHIVE: "ARCHIVE",
|
|
17
|
+
OTHER: "OTHER"
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// src/domain/resources/post/props.ts
|
|
21
|
+
var POST_TYPES = {
|
|
22
|
+
TOPIC: "TOPIC",
|
|
23
|
+
CATEGORY: "CATEGORY",
|
|
24
|
+
POST: "POST",
|
|
25
|
+
TAG: "TAG",
|
|
26
|
+
PAGE: "PAGE"
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// src/domain/resources/constants.ts
|
|
30
|
+
var ROOT_FOLDER_ID = "01ARZ3NDEKTSV4RRFFQ69G5FAV";
|
|
31
|
+
var ROOT_FOLDER_NAME = "ROOT";
|
|
32
|
+
var ROOT_FOLDER = {
|
|
33
|
+
id: ROOT_FOLDER_ID,
|
|
34
|
+
// core
|
|
35
|
+
name: ROOT_FOLDER_NAME,
|
|
36
|
+
key: "",
|
|
37
|
+
// states
|
|
38
|
+
isLocked: true,
|
|
39
|
+
// ---------------------------
|
|
40
|
+
// relations: Folder
|
|
41
|
+
// ---------------------------
|
|
42
|
+
parentFolder: null,
|
|
43
|
+
parentFolderId: null,
|
|
44
|
+
subFolders: [],
|
|
45
|
+
// ---------------------------
|
|
46
|
+
// relations: Folder
|
|
47
|
+
// ---------------------------
|
|
48
|
+
files: [],
|
|
49
|
+
// ---------------------------
|
|
50
|
+
// timestamps
|
|
51
|
+
// ---------------------------
|
|
52
|
+
createdAt: "",
|
|
53
|
+
updatedAt: ""
|
|
54
|
+
};
|
|
55
|
+
var SIMPLE_UPLOAD_FOLDER_NAME = "simple-upload";
|
|
56
|
+
var SIMPLE_UPLOAD_FOLDER_KEY = `${SIMPLE_UPLOAD_FOLDER_NAME}`;
|
|
57
|
+
var mimeToExtension = (mimeType) => {
|
|
58
|
+
if (!mimeType) return "unknown";
|
|
59
|
+
return (extension(mimeType) || "unknown").toLowerCase();
|
|
60
|
+
};
|
|
61
|
+
var ARCHIVE_MIME = /* @__PURE__ */ new Set([
|
|
62
|
+
"application/zip",
|
|
63
|
+
"application/x-rar-compressed",
|
|
64
|
+
"application/x-7z-compressed",
|
|
65
|
+
"application/gzip",
|
|
66
|
+
"application/x-tar"
|
|
67
|
+
]);
|
|
68
|
+
var classifyFileType = (mimeType, extension2) => {
|
|
69
|
+
if (!mimeType && extension2) {
|
|
70
|
+
mimeType = lookup(extension2) || void 0;
|
|
71
|
+
}
|
|
72
|
+
if (!mimeType) return FILE_TYPES.OTHER;
|
|
73
|
+
if (mimeType.startsWith("image/")) return FILE_TYPES.IMAGE;
|
|
74
|
+
if (mimeType.startsWith("video/")) return FILE_TYPES.VIDEO;
|
|
75
|
+
if (mimeType.startsWith("audio/")) return FILE_TYPES.AUDIO;
|
|
76
|
+
if (ARCHIVE_MIME.has(mimeType)) return FILE_TYPES.ARCHIVE;
|
|
77
|
+
if (mimeType.startsWith("text/") || mimeType === "application/pdf" || mimeType === "application/json" || mimeType === "application/xml") {
|
|
78
|
+
return FILE_TYPES.DOCUMENT;
|
|
79
|
+
}
|
|
80
|
+
if (mimeType.startsWith("application/")) return FILE_TYPES.DOCUMENT;
|
|
81
|
+
return FILE_TYPES.OTHER;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// src/shared/blob-file/get-media-info/get-audio-info.ts
|
|
85
|
+
function getAudioInfo(file) {
|
|
86
|
+
return new Promise((resolve, reject) => {
|
|
87
|
+
const audio = document.createElement("audio");
|
|
88
|
+
const objectUrl = URL.createObjectURL(file);
|
|
89
|
+
audio.preload = "metadata";
|
|
90
|
+
const cleanup = () => {
|
|
91
|
+
audio.removeEventListener("loadedmetadata", onLoadedMetadata);
|
|
92
|
+
audio.removeEventListener("error", onError);
|
|
93
|
+
URL.revokeObjectURL(objectUrl);
|
|
94
|
+
};
|
|
95
|
+
const onLoadedMetadata = () => {
|
|
96
|
+
const duration = audio.duration;
|
|
97
|
+
cleanup();
|
|
98
|
+
resolve({ duration });
|
|
99
|
+
};
|
|
100
|
+
const onError = () => {
|
|
101
|
+
cleanup();
|
|
102
|
+
reject(new Error("Failed to load audio metadata."));
|
|
103
|
+
};
|
|
104
|
+
audio.addEventListener("loadedmetadata", onLoadedMetadata, { once: true });
|
|
105
|
+
audio.addEventListener("error", onError, { once: true });
|
|
106
|
+
audio.src = objectUrl;
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// src/shared/blob-file/get-media-info/get-image-info.ts
|
|
111
|
+
function getImageInfo(file) {
|
|
112
|
+
return new Promise((resolve, reject) => {
|
|
113
|
+
const img = new Image();
|
|
114
|
+
const objectUrl = URL.createObjectURL(file);
|
|
115
|
+
const cleanup = () => {
|
|
116
|
+
img.removeEventListener("load", onLoad);
|
|
117
|
+
img.removeEventListener("error", onError);
|
|
118
|
+
URL.revokeObjectURL(objectUrl);
|
|
119
|
+
};
|
|
120
|
+
const onLoad = () => {
|
|
121
|
+
const width = img.naturalWidth;
|
|
122
|
+
const height = img.naturalHeight;
|
|
123
|
+
cleanup();
|
|
124
|
+
resolve({ width, height });
|
|
125
|
+
};
|
|
126
|
+
const onError = () => {
|
|
127
|
+
cleanup();
|
|
128
|
+
reject(new Error("Failed to load image for size detection."));
|
|
129
|
+
};
|
|
130
|
+
img.addEventListener("load", onLoad, { once: true });
|
|
131
|
+
img.addEventListener("error", onError, { once: true });
|
|
132
|
+
img.src = objectUrl;
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// src/shared/blob-file/get-media-info/get-video-info.ts
|
|
137
|
+
function getVideoInfo(file) {
|
|
138
|
+
return new Promise((resolve, reject) => {
|
|
139
|
+
const video = document.createElement("video");
|
|
140
|
+
const objectUrl = URL.createObjectURL(file);
|
|
141
|
+
video.preload = "metadata";
|
|
142
|
+
const cleanup = () => {
|
|
143
|
+
video.removeEventListener("loadedmetadata", onLoadedMetadata);
|
|
144
|
+
video.removeEventListener("error", onError);
|
|
145
|
+
video.src = "";
|
|
146
|
+
URL.revokeObjectURL(objectUrl);
|
|
147
|
+
};
|
|
148
|
+
const onLoadedMetadata = () => {
|
|
149
|
+
const info = {
|
|
150
|
+
width: video.videoWidth,
|
|
151
|
+
height: video.videoHeight,
|
|
152
|
+
duration: video.duration
|
|
153
|
+
};
|
|
154
|
+
cleanup();
|
|
155
|
+
resolve(info);
|
|
156
|
+
};
|
|
157
|
+
const onError = () => {
|
|
158
|
+
cleanup();
|
|
159
|
+
reject(new Error("Failed to load video metadata."));
|
|
160
|
+
};
|
|
161
|
+
video.addEventListener("loadedmetadata", onLoadedMetadata, { once: true });
|
|
162
|
+
video.addEventListener("error", onError, { once: true });
|
|
163
|
+
video.src = objectUrl;
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// src/shared/blob-file/get-media-info/get-media-info.ts
|
|
168
|
+
var IMAGE_EXT = /\.(jpe?g|png|gif|webp|bmp|avif)$/i;
|
|
169
|
+
var VIDEO_EXT = /\.(mp4|webm|mov|mkv)$/i;
|
|
170
|
+
var AUDIO_EXT = /\.(mp3|wav|ogg|m4a)$/i;
|
|
171
|
+
var getMediaInfo = async (file) => {
|
|
172
|
+
const fallback = { width: null, height: null, duration: null };
|
|
173
|
+
const mime = file.type || "";
|
|
174
|
+
const name = file instanceof File ? file.name.toLowerCase() : "";
|
|
175
|
+
try {
|
|
176
|
+
if (mime.startsWith("image/") || IMAGE_EXT.test(name)) {
|
|
177
|
+
const { width, height } = await getImageInfo(file);
|
|
178
|
+
return { width, height, duration: null };
|
|
179
|
+
}
|
|
180
|
+
if (mime.startsWith("video/") || VIDEO_EXT.test(name)) {
|
|
181
|
+
const { width, height, duration } = await getVideoInfo(file);
|
|
182
|
+
return { width, height, duration };
|
|
183
|
+
}
|
|
184
|
+
if (mime.startsWith("audio/") || AUDIO_EXT.test(name)) {
|
|
185
|
+
const { duration } = await getAudioInfo(file);
|
|
186
|
+
return { width: null, height: null, duration };
|
|
187
|
+
}
|
|
188
|
+
return fallback;
|
|
189
|
+
} catch {
|
|
190
|
+
return fallback;
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
// src/shared/blob-file/format-file-size.ts
|
|
195
|
+
var formatFileSize = (size, decimals = 2) => {
|
|
196
|
+
const units = ["B", "KB", "MB", "GB", "TB"];
|
|
197
|
+
let value = size;
|
|
198
|
+
let unitIndex = 0;
|
|
199
|
+
while (value >= 1024 && unitIndex < units.length - 1) {
|
|
200
|
+
value /= 1024;
|
|
201
|
+
unitIndex++;
|
|
202
|
+
}
|
|
203
|
+
const display = unitIndex === 0 ? value.toString() : value.toFixed(decimals);
|
|
204
|
+
return `${display} ${units[unitIndex]}`;
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
export { ADMIN_ROLES, FILE_TYPES, POST_TYPES, ROOT_FOLDER, ROOT_FOLDER_ID, ROOT_FOLDER_NAME, SIMPLE_UPLOAD_FOLDER_KEY, SIMPLE_UPLOAD_FOLDER_NAME, classifyFileType, formatFileSize, getMediaInfo, mimeToExtension };
|