freebeat-mcp 0.1.0
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/LICENSE +21 -0
- package/README.md +210 -0
- package/dist/capabilities/assets/register.d.ts +3 -0
- package/dist/capabilities/assets/register.js +7 -0
- package/dist/capabilities/assets/register.js.map +1 -0
- package/dist/capabilities/assets/tools/upload-audio.d.ts +3 -0
- package/dist/capabilities/assets/tools/upload-audio.js +70 -0
- package/dist/capabilities/assets/tools/upload-audio.js.map +1 -0
- package/dist/capabilities/assets/tools/upload-image.d.ts +3 -0
- package/dist/capabilities/assets/tools/upload-image.js +67 -0
- package/dist/capabilities/assets/tools/upload-image.js.map +1 -0
- package/dist/capabilities/effects/register.d.ts +3 -0
- package/dist/capabilities/effects/register.js +7 -0
- package/dist/capabilities/effects/register.js.map +1 -0
- package/dist/capabilities/effects/task-type.d.ts +1 -0
- package/dist/capabilities/effects/task-type.js +2 -0
- package/dist/capabilities/effects/task-type.js.map +1 -0
- package/dist/capabilities/effects/tools/generate-effect.d.ts +3 -0
- package/dist/capabilities/effects/tools/generate-effect.js +81 -0
- package/dist/capabilities/effects/tools/generate-effect.js.map +1 -0
- package/dist/capabilities/effects/tools/list-effects.d.ts +3 -0
- package/dist/capabilities/effects/tools/list-effects.js +55 -0
- package/dist/capabilities/effects/tools/list-effects.js.map +1 -0
- package/dist/capabilities/mv/register.d.ts +3 -0
- package/dist/capabilities/mv/register.js +5 -0
- package/dist/capabilities/mv/register.js.map +1 -0
- package/dist/capabilities/mv/task-type.d.ts +1 -0
- package/dist/capabilities/mv/task-type.js +2 -0
- package/dist/capabilities/mv/task-type.js.map +1 -0
- package/dist/capabilities/mv/tools/generate-music-video.d.ts +3 -0
- package/dist/capabilities/mv/tools/generate-music-video.js +116 -0
- package/dist/capabilities/mv/tools/generate-music-video.js.map +1 -0
- package/dist/capabilities/tasks/register.d.ts +3 -0
- package/dist/capabilities/tasks/register.js +7 -0
- package/dist/capabilities/tasks/register.js.map +1 -0
- package/dist/capabilities/tasks/task-type.d.ts +1 -0
- package/dist/capabilities/tasks/task-type.js +2 -0
- package/dist/capabilities/tasks/task-type.js.map +1 -0
- package/dist/capabilities/tasks/tools/get-task-result.d.ts +3 -0
- package/dist/capabilities/tasks/tools/get-task-result.js +93 -0
- package/dist/capabilities/tasks/tools/get-task-result.js.map +1 -0
- package/dist/capabilities/tasks/tools/get-task-status.d.ts +3 -0
- package/dist/capabilities/tasks/tools/get-task-status.js +63 -0
- package/dist/capabilities/tasks/tools/get-task-status.js.map +1 -0
- package/dist/core/config.d.ts +4 -0
- package/dist/core/config.js +11 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/errors.d.ts +6 -0
- package/dist/core/errors.js +35 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/prompt.d.ts +1 -0
- package/dist/core/prompt.js +12 -0
- package/dist/core/prompt.js.map +1 -0
- package/dist/core/response.d.ts +14 -0
- package/dist/core/response.js +26 -0
- package/dist/core/response.js.map +1 -0
- package/dist/core/task-types.d.ts +6 -0
- package/dist/core/task-types.js +20 -0
- package/dist/core/task-types.js.map +1 -0
- package/dist/core/tasks.d.ts +1 -0
- package/dist/core/tasks.js +2 -0
- package/dist/core/tasks.js.map +1 -0
- package/dist/core/tool-schemas.d.ts +7 -0
- package/dist/core/tool-schemas.js +64 -0
- package/dist/core/tool-schemas.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/services/freebeat-api.d.ts +117 -0
- package/dist/services/freebeat-api.js +188 -0
- package/dist/services/freebeat-api.js.map +1 -0
- package/dist/services/upload-service.d.ts +13 -0
- package/dist/services/upload-service.js +22 -0
- package/dist/services/upload-service.js.map +1 -0
- package/dist/utils/file.d.ts +5 -0
- package/dist/utils/file.js +69 -0
- package/dist/utils/file.js.map +1 -0
- package/package.json +48 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { SessionType } from "../core/task-types.js";
|
|
3
|
+
declare const preSignedUrlItemSchema: z.ZodObject<{
|
|
4
|
+
signURL: z.ZodString;
|
|
5
|
+
finalStaticUrl: z.ZodString;
|
|
6
|
+
}, "strip", z.ZodTypeAny, {
|
|
7
|
+
signURL: string;
|
|
8
|
+
finalStaticUrl: string;
|
|
9
|
+
}, {
|
|
10
|
+
signURL: string;
|
|
11
|
+
finalStaticUrl: string;
|
|
12
|
+
}>;
|
|
13
|
+
declare const taskStartResponseSchema: z.ZodObject<{
|
|
14
|
+
task_id: z.ZodString;
|
|
15
|
+
status: z.ZodString;
|
|
16
|
+
task_type: z.ZodString;
|
|
17
|
+
}, "strip", z.ZodTypeAny, {
|
|
18
|
+
status: string;
|
|
19
|
+
task_id: string;
|
|
20
|
+
task_type: string;
|
|
21
|
+
}, {
|
|
22
|
+
status: string;
|
|
23
|
+
task_id: string;
|
|
24
|
+
task_type: string;
|
|
25
|
+
}>;
|
|
26
|
+
declare const effectListItemSchema: z.ZodObject<{
|
|
27
|
+
aspectRatio: z.ZodString;
|
|
28
|
+
coverUrl: z.ZodString;
|
|
29
|
+
effectsDisplayName: z.ZodString;
|
|
30
|
+
effectsName: z.ZodString;
|
|
31
|
+
effectsTypeId: z.ZodNumber;
|
|
32
|
+
height: z.ZodNumber;
|
|
33
|
+
id: z.ZodNumber;
|
|
34
|
+
musicId: z.ZodNumber;
|
|
35
|
+
musicName: z.ZodString;
|
|
36
|
+
musicUrl: z.ZodString;
|
|
37
|
+
videoUrl: z.ZodString;
|
|
38
|
+
width: z.ZodNumber;
|
|
39
|
+
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
40
|
+
aspectRatio: z.ZodString;
|
|
41
|
+
coverUrl: z.ZodString;
|
|
42
|
+
effectsDisplayName: z.ZodString;
|
|
43
|
+
effectsName: z.ZodString;
|
|
44
|
+
effectsTypeId: z.ZodNumber;
|
|
45
|
+
height: z.ZodNumber;
|
|
46
|
+
id: z.ZodNumber;
|
|
47
|
+
musicId: z.ZodNumber;
|
|
48
|
+
musicName: z.ZodString;
|
|
49
|
+
musicUrl: z.ZodString;
|
|
50
|
+
videoUrl: z.ZodString;
|
|
51
|
+
width: z.ZodNumber;
|
|
52
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
53
|
+
aspectRatio: z.ZodString;
|
|
54
|
+
coverUrl: z.ZodString;
|
|
55
|
+
effectsDisplayName: z.ZodString;
|
|
56
|
+
effectsName: z.ZodString;
|
|
57
|
+
effectsTypeId: z.ZodNumber;
|
|
58
|
+
height: z.ZodNumber;
|
|
59
|
+
id: z.ZodNumber;
|
|
60
|
+
musicId: z.ZodNumber;
|
|
61
|
+
musicName: z.ZodString;
|
|
62
|
+
musicUrl: z.ZodString;
|
|
63
|
+
videoUrl: z.ZodString;
|
|
64
|
+
width: z.ZodNumber;
|
|
65
|
+
}, z.ZodTypeAny, "passthrough">>;
|
|
66
|
+
type PreSignedUrlResponse = z.infer<typeof preSignedUrlItemSchema>;
|
|
67
|
+
export type TaskStartResponse = z.infer<typeof taskStartResponseSchema>;
|
|
68
|
+
export interface TaskStatusResponse {
|
|
69
|
+
task_id: string;
|
|
70
|
+
status: string;
|
|
71
|
+
type: SessionType;
|
|
72
|
+
error_message?: string;
|
|
73
|
+
error_code?: number | string;
|
|
74
|
+
}
|
|
75
|
+
export interface TaskResultResponse {
|
|
76
|
+
task_id: string;
|
|
77
|
+
status: string;
|
|
78
|
+
type: SessionType;
|
|
79
|
+
error_message?: string;
|
|
80
|
+
error_code?: number | string;
|
|
81
|
+
result_payload?: string;
|
|
82
|
+
}
|
|
83
|
+
export type EffectListItem = z.infer<typeof effectListItemSchema>;
|
|
84
|
+
export interface GenerateMusicVideoParams {
|
|
85
|
+
music_id: number;
|
|
86
|
+
prompt: string;
|
|
87
|
+
aspect_ratio?: string;
|
|
88
|
+
resolution?: number;
|
|
89
|
+
start_ms?: number;
|
|
90
|
+
end_ms?: number;
|
|
91
|
+
reference_image_urls?: string[];
|
|
92
|
+
mv_type?: "abstract" | "singing" | "storytelling";
|
|
93
|
+
style?: string;
|
|
94
|
+
watermark?: boolean;
|
|
95
|
+
}
|
|
96
|
+
export interface GenerateEffectParams {
|
|
97
|
+
effect_id: number;
|
|
98
|
+
music_id: number;
|
|
99
|
+
prompt: string;
|
|
100
|
+
watermark?: boolean;
|
|
101
|
+
reference_image_urls: string[];
|
|
102
|
+
}
|
|
103
|
+
export declare class FreebeatApiClient {
|
|
104
|
+
private httpClient;
|
|
105
|
+
constructor(baseUrl: string, apiKey: string);
|
|
106
|
+
private unwrapApiEnvelope;
|
|
107
|
+
private postAndUnwrap;
|
|
108
|
+
createUploadUrl(key: string, fileName: string, bucketName?: string): Promise<PreSignedUrlResponse>;
|
|
109
|
+
uploadToPreSignedUrl(signURL: string, fileBuffer: Buffer, contentType: string): Promise<void>;
|
|
110
|
+
saveMusicSource(copyUrl: string): Promise<number>;
|
|
111
|
+
listEffects(): Promise<EffectListItem[]>;
|
|
112
|
+
generateMusicVideo(params: GenerateMusicVideoParams): Promise<TaskStartResponse>;
|
|
113
|
+
generateEffect(params: GenerateEffectParams): Promise<TaskStartResponse>;
|
|
114
|
+
getTaskStatus(taskId: string): Promise<TaskStatusResponse>;
|
|
115
|
+
getTaskResult(taskId: string): Promise<TaskResultResponse>;
|
|
116
|
+
}
|
|
117
|
+
export {};
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { AppError } from "../core/errors.js";
|
|
4
|
+
import { EFFECT_SESSION_TYPE, EFFECT_TASK_TYPE, MUSIC_VIDEO_SESSION_TYPE, MUSIC_VIDEO_TASK_TYPE, } from "../core/task-types.js";
|
|
5
|
+
const preSignedUrlItemSchema = z.object({
|
|
6
|
+
signURL: z.string(),
|
|
7
|
+
finalStaticUrl: z.string(),
|
|
8
|
+
});
|
|
9
|
+
const apiResponseEnvelopeSchema = z.object({
|
|
10
|
+
code: z.number(),
|
|
11
|
+
msg: z.string().optional(),
|
|
12
|
+
data: z.unknown().optional(),
|
|
13
|
+
});
|
|
14
|
+
const preSignedUrlListSchema = z.array(preSignedUrlItemSchema).min(1);
|
|
15
|
+
const taskStartResponseSchema = z.object({
|
|
16
|
+
task_id: z.string(),
|
|
17
|
+
status: z.string(),
|
|
18
|
+
task_type: z.string(),
|
|
19
|
+
});
|
|
20
|
+
const trackIdResponseSchema = z.object({
|
|
21
|
+
trackId: z.string(),
|
|
22
|
+
});
|
|
23
|
+
const sessionTypeSchema = z.union([z.number(), z.string()]);
|
|
24
|
+
const errorCodeSchema = z.union([z.number().int(), z.string()]);
|
|
25
|
+
const querySessionStatusResponseSchema = z.object({
|
|
26
|
+
status: z.string(),
|
|
27
|
+
trackId: z.string().optional(),
|
|
28
|
+
type: sessionTypeSchema,
|
|
29
|
+
errorMsg: z.string().optional(),
|
|
30
|
+
errorCode: errorCodeSchema.optional(),
|
|
31
|
+
}).passthrough();
|
|
32
|
+
const querySessionResultResponseSchema = querySessionStatusResponseSchema.extend({
|
|
33
|
+
resultPayload: z.string().optional(),
|
|
34
|
+
}).passthrough();
|
|
35
|
+
const effectListItemSchema = z.object({
|
|
36
|
+
aspectRatio: z.string(),
|
|
37
|
+
coverUrl: z.string(),
|
|
38
|
+
effectsDisplayName: z.string(),
|
|
39
|
+
effectsName: z.string(),
|
|
40
|
+
effectsTypeId: z.number(),
|
|
41
|
+
height: z.number(),
|
|
42
|
+
id: z.number(),
|
|
43
|
+
musicId: z.number(),
|
|
44
|
+
musicName: z.string(),
|
|
45
|
+
musicUrl: z.string(),
|
|
46
|
+
videoUrl: z.string(),
|
|
47
|
+
width: z.number(),
|
|
48
|
+
}).passthrough();
|
|
49
|
+
const effectListResponseSchema = z.object({
|
|
50
|
+
anchor: z.union([z.string(), z.number()]).optional(),
|
|
51
|
+
end: z.boolean().optional(),
|
|
52
|
+
list: z.array(effectListItemSchema),
|
|
53
|
+
});
|
|
54
|
+
export class FreebeatApiClient {
|
|
55
|
+
httpClient;
|
|
56
|
+
constructor(baseUrl, apiKey) {
|
|
57
|
+
this.httpClient = axios.create({
|
|
58
|
+
baseURL: baseUrl,
|
|
59
|
+
timeout: 30_000,
|
|
60
|
+
headers: {
|
|
61
|
+
Authorization: apiKey,
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
unwrapApiEnvelope(payload, dataSchema, action, invalidDataMessage = `${action}: unexpected response format`) {
|
|
66
|
+
const envelope = apiResponseEnvelopeSchema.safeParse(payload);
|
|
67
|
+
if (!envelope.success) {
|
|
68
|
+
throw new AppError(`${action}: unexpected response format`, "INVALID_RESPONSE");
|
|
69
|
+
}
|
|
70
|
+
if (envelope.data.code !== 0) {
|
|
71
|
+
throw new AppError(`${action} failed: ${envelope.data.msg ?? "unknown error"}`, "API_ERROR");
|
|
72
|
+
}
|
|
73
|
+
if (envelope.data.data === undefined) {
|
|
74
|
+
throw new AppError(invalidDataMessage, "INVALID_RESPONSE");
|
|
75
|
+
}
|
|
76
|
+
const parsedData = dataSchema.safeParse(envelope.data.data);
|
|
77
|
+
if (!parsedData.success) {
|
|
78
|
+
throw new AppError(invalidDataMessage, "INVALID_RESPONSE");
|
|
79
|
+
}
|
|
80
|
+
return parsedData.data;
|
|
81
|
+
}
|
|
82
|
+
async postAndUnwrap(path, body, dataSchema, action, invalidDataMessage = `${action}: unexpected response format`) {
|
|
83
|
+
const response = await this.httpClient.post(path, body);
|
|
84
|
+
return this.unwrapApiEnvelope(response.data, dataSchema, action, invalidDataMessage);
|
|
85
|
+
}
|
|
86
|
+
async createUploadUrl(key, fileName, bucketName = "") {
|
|
87
|
+
const list = await this.postAndUnwrap("/v1/mcp/agent/genUploadSignUrl", { reqList: [{ key, fileName, bucketName }] }, preSignedUrlListSchema, "createUploadUrl");
|
|
88
|
+
return list[0];
|
|
89
|
+
}
|
|
90
|
+
async uploadToPreSignedUrl(signURL, fileBuffer, contentType) {
|
|
91
|
+
const uploadHeaders = {
|
|
92
|
+
"Content-Type": contentType,
|
|
93
|
+
};
|
|
94
|
+
const signedHeaders = new URL(signURL).searchParams
|
|
95
|
+
.get("X-Amz-SignedHeaders")
|
|
96
|
+
?.split(";")
|
|
97
|
+
.map((header) => header.trim().toLowerCase()) ?? [];
|
|
98
|
+
if (signedHeaders.includes("x-amz-acl")) {
|
|
99
|
+
uploadHeaders["x-amz-acl"] = "public-read";
|
|
100
|
+
}
|
|
101
|
+
await axios.put(signURL, fileBuffer, {
|
|
102
|
+
headers: uploadHeaders,
|
|
103
|
+
timeout: 300_000,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
async saveMusicSource(copyUrl) {
|
|
107
|
+
return this.postAndUnwrap("/v1/mcp/agent/saveMusicV3", { copyUrl }, z.number(), "saveMusicSource");
|
|
108
|
+
}
|
|
109
|
+
async listEffects() {
|
|
110
|
+
const result = await this.postAndUnwrap("/v1/mcp/agent/getAiAgentVeEffectsVideoList", {
|
|
111
|
+
anchor: 1,
|
|
112
|
+
limit: 1000,
|
|
113
|
+
effectsTypeIdList: [],
|
|
114
|
+
maxTypeCount: 1,
|
|
115
|
+
}, effectListResponseSchema, "listEffects");
|
|
116
|
+
return result.list;
|
|
117
|
+
}
|
|
118
|
+
async generateMusicVideo(params) {
|
|
119
|
+
if (!Number.isInteger(params.music_id)) {
|
|
120
|
+
throw new AppError("generateMusicVideo: music_id must be an integer", "INVALID_PARAMS");
|
|
121
|
+
}
|
|
122
|
+
if (params.resolution !== undefined && ![720, 1080].includes(params.resolution)) {
|
|
123
|
+
throw new AppError("generateMusicVideo: resolution must be either 720 or 1080", "INVALID_PARAMS");
|
|
124
|
+
}
|
|
125
|
+
const response = await this.postAndUnwrap("/v1/mcp/openMv/createSession", {
|
|
126
|
+
type: MUSIC_VIDEO_SESSION_TYPE,
|
|
127
|
+
mvMode: "fast",
|
|
128
|
+
mvType: params.mv_type,
|
|
129
|
+
style: params.style,
|
|
130
|
+
musicId: params.music_id,
|
|
131
|
+
musicStartMs: params.start_ms,
|
|
132
|
+
musicEndMs: params.end_ms,
|
|
133
|
+
prompt: params.prompt,
|
|
134
|
+
aspectRatio: params.aspect_ratio,
|
|
135
|
+
resolution: params.resolution,
|
|
136
|
+
watermark: params.watermark,
|
|
137
|
+
personaImgUrls: params.reference_image_urls,
|
|
138
|
+
}, trackIdResponseSchema, "generateMusicVideo", "generateMusicVideo: missing trackId in response");
|
|
139
|
+
return {
|
|
140
|
+
task_id: response.trackId,
|
|
141
|
+
task_type: MUSIC_VIDEO_TASK_TYPE,
|
|
142
|
+
status: "pending",
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
async generateEffect(params) {
|
|
146
|
+
if (!Number.isInteger(params.effect_id)) {
|
|
147
|
+
throw new AppError("generateEffect: effect_id must be an integer", "INVALID_PARAMS");
|
|
148
|
+
}
|
|
149
|
+
if (!Number.isInteger(params.music_id)) {
|
|
150
|
+
throw new AppError("generateEffect: music_id must be an integer", "INVALID_PARAMS");
|
|
151
|
+
}
|
|
152
|
+
const response = await this.postAndUnwrap("/v1/mcp/openMv/createSession", {
|
|
153
|
+
type: EFFECT_SESSION_TYPE,
|
|
154
|
+
effectsTypeId: params.effect_id,
|
|
155
|
+
musicId: params.music_id,
|
|
156
|
+
prompt: params.prompt,
|
|
157
|
+
watermark: params.watermark,
|
|
158
|
+
personaImgUrls: params.reference_image_urls,
|
|
159
|
+
}, trackIdResponseSchema, "generateEffect", "generateEffect: missing trackId in response");
|
|
160
|
+
return {
|
|
161
|
+
task_id: response.trackId,
|
|
162
|
+
task_type: EFFECT_TASK_TYPE,
|
|
163
|
+
status: "pending",
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
async getTaskStatus(taskId) {
|
|
167
|
+
const parsed = await this.postAndUnwrap("/v1/mcp/openMv/querySessionStatus", { trackId: taskId }, querySessionStatusResponseSchema, "getTaskStatus", "getTaskStatus: unexpected session status response");
|
|
168
|
+
return {
|
|
169
|
+
task_id: parsed.trackId ?? taskId,
|
|
170
|
+
status: parsed.status,
|
|
171
|
+
type: parsed.type,
|
|
172
|
+
error_message: parsed.errorMsg,
|
|
173
|
+
error_code: parsed.errorCode,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
async getTaskResult(taskId) {
|
|
177
|
+
const parsed = await this.postAndUnwrap("/v1/mcp/openMv/querySessionResult", { trackId: taskId }, querySessionResultResponseSchema, "getTaskResult", "getTaskResult: unexpected session result response");
|
|
178
|
+
return {
|
|
179
|
+
task_id: parsed.trackId ?? taskId,
|
|
180
|
+
status: parsed.status,
|
|
181
|
+
type: parsed.type,
|
|
182
|
+
error_message: parsed.errorMsg,
|
|
183
|
+
error_code: parsed.errorCode,
|
|
184
|
+
result_payload: parsed.resultPayload,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=freebeat-api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"freebeat-api.js","sourceRoot":"","sources":["../../src/services/freebeat-api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { FreebeatApiClient } from "./freebeat-api.js";
|
|
2
|
+
export interface UploadLocalFileParams {
|
|
3
|
+
filePath: string;
|
|
4
|
+
keyPrefix: string;
|
|
5
|
+
bucketName?: string;
|
|
6
|
+
contentType: string;
|
|
7
|
+
keySuffix?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare class UploadService {
|
|
10
|
+
private readonly client;
|
|
11
|
+
constructor(client: Pick<FreebeatApiClient, "createUploadUrl" | "uploadToPreSignedUrl">);
|
|
12
|
+
uploadLocalFile({ filePath, keyPrefix, bucketName, contentType, keySuffix, }: UploadLocalFileParams): Promise<string>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { safeExtension } from "../utils/file.js";
|
|
4
|
+
export class UploadService {
|
|
5
|
+
client;
|
|
6
|
+
constructor(client) {
|
|
7
|
+
this.client = client;
|
|
8
|
+
}
|
|
9
|
+
async uploadLocalFile({ filePath, keyPrefix, bucketName = "freebeat-static", contentType, keySuffix, }) {
|
|
10
|
+
const filename = path.basename(filePath);
|
|
11
|
+
const ext = safeExtension(filePath);
|
|
12
|
+
const timestamp = Date.now();
|
|
13
|
+
const rand = Math.random().toString(36).slice(2, 8);
|
|
14
|
+
const suffix = keySuffix ? `_${keySuffix}` : "";
|
|
15
|
+
const key = `${keyPrefix}/${timestamp}${suffix}_${rand}.${ext}`;
|
|
16
|
+
const { signURL, finalStaticUrl } = await this.client.createUploadUrl(key, filename, bucketName);
|
|
17
|
+
const fileBuffer = await fs.promises.readFile(filePath);
|
|
18
|
+
await this.client.uploadToPreSignedUrl(signURL, fileBuffer, contentType);
|
|
19
|
+
return finalStaticUrl;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=upload-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload-service.js","sourceRoot":"","sources":["../../src/services/upload-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAUjD,MAAM,OAAO,aAAa;IACK;IAA7B,YAA6B,MAG5B;QAH4B,WAAM,GAAN,MAAM,CAGlC;IAAG,CAAC;IAEL,KAAK,CAAC,eAAe,CAAC,EACpB,QAAQ,EACR,SAAS,EACT,UAAU,GAAG,iBAAiB,EAC9B,WAAW,EACX,SAAS,GACa;QACtB,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACzC,MAAM,GAAG,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;QACpC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACpD,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChD,MAAM,GAAG,GAAG,GAAG,SAAS,IAAI,SAAS,GAAG,MAAM,IAAI,IAAI,IAAI,GAAG,EAAE,CAAC;QAEhE,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,eAAe,CACnE,GAAG,EACH,QAAQ,EACR,UAAU,CACX,CAAC;QAEF,MAAM,UAAU,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACxD,MAAM,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC,OAAO,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;QAEzE,OAAO,cAAc,CAAC;IACxB,CAAC;CACF"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function detectAudioMimeType(filePath: string): string;
|
|
2
|
+
export declare function detectImageMimeType(filePath: string): string;
|
|
3
|
+
export declare function safeExtension(filePath: string): string;
|
|
4
|
+
export declare function validateAudioFile(filePath: string): void;
|
|
5
|
+
export declare function validateImageFile(filePath: string): void;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import mime from "mime-types";
|
|
4
|
+
import { AppError } from "../core/errors.js";
|
|
5
|
+
const AUDIO_CONFIG = {
|
|
6
|
+
acceptedTypes: [
|
|
7
|
+
"audio/mpeg",
|
|
8
|
+
"audio/wav",
|
|
9
|
+
"audio/ogg",
|
|
10
|
+
"audio/flac",
|
|
11
|
+
"audio/aac",
|
|
12
|
+
],
|
|
13
|
+
normalizeMap: {
|
|
14
|
+
"audio/wave": "audio/wav",
|
|
15
|
+
"audio/x-flac": "audio/flac",
|
|
16
|
+
"audio/x-aac": "audio/aac",
|
|
17
|
+
},
|
|
18
|
+
maxSize: 50 * 1024 * 1024,
|
|
19
|
+
label: "audio",
|
|
20
|
+
};
|
|
21
|
+
const IMAGE_CONFIG = {
|
|
22
|
+
acceptedTypes: ["image/png", "image/jpeg"],
|
|
23
|
+
normalizeMap: {
|
|
24
|
+
"image/jpg": "image/jpeg",
|
|
25
|
+
},
|
|
26
|
+
maxSize: 10 * 1024 * 1024,
|
|
27
|
+
label: "image",
|
|
28
|
+
};
|
|
29
|
+
function detectMime(filePath, normalizeMap) {
|
|
30
|
+
const mimeType = mime.lookup(filePath);
|
|
31
|
+
if (!mimeType) {
|
|
32
|
+
throw new AppError(`Cannot detect MIME type for file: ${filePath}`, "INVALID_PARAMS");
|
|
33
|
+
}
|
|
34
|
+
return normalizeMap[mimeType] ?? mimeType;
|
|
35
|
+
}
|
|
36
|
+
function validateFile(filePath, config) {
|
|
37
|
+
if (!fs.existsSync(filePath)) {
|
|
38
|
+
throw new AppError(`File not found: ${filePath}`, "FILE_NOT_FOUND");
|
|
39
|
+
}
|
|
40
|
+
const mimeType = detectMime(filePath, config.normalizeMap);
|
|
41
|
+
if (!config.acceptedTypes.includes(mimeType)) {
|
|
42
|
+
throw new AppError(`Unsupported ${config.label} type: ${mimeType}. Accepted: ${config.acceptedTypes.join(", ")}`, "UNSUPPORTED_TYPE");
|
|
43
|
+
}
|
|
44
|
+
const stats = fs.statSync(filePath);
|
|
45
|
+
if (stats.size > config.maxSize) {
|
|
46
|
+
const maxMB = config.maxSize / 1024 / 1024;
|
|
47
|
+
throw new AppError(`File too large: ${(stats.size / 1024 / 1024).toFixed(2)}MB. Max: ${maxMB}MB`, "FILE_TOO_LARGE");
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
export function detectAudioMimeType(filePath) {
|
|
51
|
+
return detectMime(filePath, AUDIO_CONFIG.normalizeMap);
|
|
52
|
+
}
|
|
53
|
+
export function detectImageMimeType(filePath) {
|
|
54
|
+
return detectMime(filePath, IMAGE_CONFIG.normalizeMap);
|
|
55
|
+
}
|
|
56
|
+
export function safeExtension(filePath) {
|
|
57
|
+
const ext = path.extname(filePath).slice(1).toLowerCase();
|
|
58
|
+
if (!/^[a-z0-9]+$/.test(ext)) {
|
|
59
|
+
throw new AppError(`Invalid file extension: ${ext}`, "INVALID_PARAMS");
|
|
60
|
+
}
|
|
61
|
+
return ext;
|
|
62
|
+
}
|
|
63
|
+
export function validateAudioFile(filePath) {
|
|
64
|
+
validateFile(filePath, AUDIO_CONFIG);
|
|
65
|
+
}
|
|
66
|
+
export function validateImageFile(filePath) {
|
|
67
|
+
validateFile(filePath, IMAGE_CONFIG);
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=file.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file.js","sourceRoot":"","sources":["../../src/utils/file.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "freebeat-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Freebeat MCP Server",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"freebeat-mcp": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "./dist/index.js",
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"start": "node dist/index.js",
|
|
13
|
+
"dev": "tsx src/index.ts",
|
|
14
|
+
"pretest": "npm run build",
|
|
15
|
+
"test": "vitest run",
|
|
16
|
+
"test:watch": "vitest",
|
|
17
|
+
"prepublishOnly": "npm run build"
|
|
18
|
+
},
|
|
19
|
+
"keywords": ["mcp", "freebeat", "ai", "music-video"],
|
|
20
|
+
"author": "Freebeat",
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "git+https://github.com/freebeatfit/freebeat-mcp.git"
|
|
25
|
+
},
|
|
26
|
+
"homepage": "https://github.com/freebeatfit/freebeat-mcp#readme",
|
|
27
|
+
"bugs": {
|
|
28
|
+
"url": "https://github.com/freebeatfit/freebeat-mcp/issues"
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"dist",
|
|
32
|
+
"README.md",
|
|
33
|
+
"LICENSE"
|
|
34
|
+
],
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@modelcontextprotocol/sdk": "^1.25.0",
|
|
37
|
+
"axios": "^1.7.0",
|
|
38
|
+
"mime-types": "^2.1.35",
|
|
39
|
+
"zod": "^3.23.0"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/mime-types": "^2.1.4",
|
|
43
|
+
"@types/node": "^20.0.0",
|
|
44
|
+
"tsx": "^4.0.0",
|
|
45
|
+
"typescript": "^5.5.0",
|
|
46
|
+
"vitest": "^3.0.0"
|
|
47
|
+
}
|
|
48
|
+
}
|