diff --git a/README.md b/README.md index ccc31bb..40d813b 100644 --- a/README.md +++ b/README.md @@ -159,6 +159,7 @@ Suno API currently mainly implements the following APIs: - `/api/get_aligned_lyrics`: Get list of timestamps for each word in the lyrics - `/api/clip`: Get clip information based on ID passed as query parameter `id` - `/api/concat`: Generate the whole song from extensions +- `/api/projects`: Get a list of projects ``` You can also specify the cookies in the `Cookie` header of your request, overriding the default cookies in the `SUNO_COOKIE` environment variable. This comes in handy when, for example, you want to use multiple free accounts at the same time. diff --git a/src/app/api/projects/route.ts b/src/app/api/projects/route.ts new file mode 100644 index 0000000..b224afb --- /dev/null +++ b/src/app/api/projects/route.ts @@ -0,0 +1,54 @@ +import { NextResponse, NextRequest } from 'next/server'; +import { cookies } from 'next/headers'; +import { sunoApi } from '@/lib/SunoApi'; +import { corsHeaders } from '@/lib/utils'; + +export const dynamic = 'force-dynamic'; + +export async function GET(req: NextRequest) { + if (req.method === 'GET') { + try { + const url = new URL(req.url); + const page = url.searchParams.get('page') || '1'; + const cookie = (await cookies()).toString(); + + const data = await (await sunoApi(cookie)).projects(parseInt(page)); + + return new NextResponse(JSON.stringify(data), { + status: 200, + headers: { + 'Content-Type': 'application/json', + ...corsHeaders + } + }); + } catch (error) { + console.error('Error fetching projects:', error); + + return new NextResponse( + JSON.stringify({ error: 'Internal server error' }), + { + status: 500, + headers: { + 'Content-Type': 'application/json', + ...corsHeaders + } + } + ); + } + } else { + return new NextResponse('Method Not Allowed', { + headers: { + Allow: 'GET', + ...corsHeaders + }, + status: 405 + }); + } +} + +export async function OPTIONS(request: Request) { + return new Response(null, { + status: 200, + headers: corsHeaders + }); +} \ No newline at end of file diff --git a/src/app/docs/swagger-suno-api.json b/src/app/docs/swagger-suno-api.json index fbc03ea..135022f 100644 --- a/src/app/docs/swagger-suno-api.json +++ b/src/app/docs/swagger-suno-api.json @@ -378,6 +378,87 @@ } } }, + "/api/projects": { + "get": { + "summary": "Get user's projects", + "description": "Retrieves the user's projects from Suno API.", + "tags": ["default"], + "parameters": [ + { + "in": "query", + "name": "page", + "description": "Page number (defaults to 1)", + "required": false, + "schema": { + "type": "number", + "default": 1 + } + } + ], + "responses": { + "200": { + "description": "success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "projects": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Project ID" + }, + "name": { + "type": "string", + "description": "Project name" + }, + "created_at": { + "type": "string", + "description": "Creation date and time" + }, + "last_modified": { + "type": "string", + "description": "Last modification date and time" + } + } + } + }, + "total_results": { + "type": "integer", + "description": "Total number of projects" + }, + "current_page": { + "type": "integer", + "description": "Current page number" + } + } + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Internal server error" + } + } + } + } + } + } + } + } + }, "/api/get_limit": { "get": { "summary": "Get quota information.", diff --git a/src/lib/SunoApi.ts b/src/lib/SunoApi.ts index f01ac72..9389f1a 100644 --- a/src/lib/SunoApi.ts +++ b/src/lib/SunoApi.ts @@ -847,6 +847,29 @@ class SunoApi { return response.data; } + + /** + * Retrieves user's projects from Suno API. + * @param page An optional page number to retrieve projects from (default: 1). + * @returns A promise that resolves to the projects data from Suno. + */ + public async projects(page: number = 1): Promise { + await this.keepAlive(false); + + const url = `${SunoApi.BASE_URL}/api/project/me?page=${page}`; + + logger.info(`Fetching projects data: ${url}`); + + const response = await this.client.get(url, { + timeout: 10000 // 10 seconds timeout + }); + + if (response.status !== 200) { + throw new Error('Error response: ' + response.statusText); + } + + return response.data; + } } export const sunoApi = async (cookie?: string) => {