Merge pull request #178 from WSeubring/feature/add-page-query-param-to-get
Feature: add page query param to get
This commit is contained in:
commit
9941933771
4
.prettierrc
Normal file
4
.prettierrc
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"trailingComma": "none",
|
||||||
|
"singleQuote": true
|
||||||
|
}
|
@ -1,20 +1,22 @@
|
|||||||
import { NextResponse, NextRequest } from "next/server";
|
import { NextResponse, NextRequest } from 'next/server';
|
||||||
import { sunoApi } from "@/lib/SunoApi";
|
import { sunoApi } from '@/lib/SunoApi';
|
||||||
import { corsHeaders } from "@/lib/utils";
|
import { corsHeaders } from '@/lib/utils';
|
||||||
|
|
||||||
export const dynamic = "force-dynamic";
|
export const dynamic = 'force-dynamic';
|
||||||
|
|
||||||
export async function GET(req: NextRequest) {
|
export async function GET(req: NextRequest) {
|
||||||
if (req.method === 'GET') {
|
if (req.method === 'GET') {
|
||||||
try {
|
try {
|
||||||
const url = new URL(req.url);
|
const url = new URL(req.url);
|
||||||
const songIds = url.searchParams.get('ids');
|
const songIds = url.searchParams.get('ids');
|
||||||
|
const page = url.searchParams.get('page');
|
||||||
|
|
||||||
let audioInfo = [];
|
let audioInfo = [];
|
||||||
if (songIds && songIds.length > 0) {
|
if (songIds && songIds.length > 0) {
|
||||||
const idsArray = songIds.split(',');
|
const idsArray = songIds.split(',');
|
||||||
audioInfo = await (await sunoApi).get(idsArray);
|
audioInfo = await (await sunoApi).get(idsArray, page);
|
||||||
} else {
|
} else {
|
||||||
audioInfo = await (await sunoApi).get();
|
audioInfo = await (await sunoApi).get(undefined, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new NextResponse(JSON.stringify(audioInfo), {
|
return new NextResponse(JSON.stringify(audioInfo), {
|
||||||
@ -27,13 +29,16 @@ export async function GET(req: NextRequest) {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching audio:', error);
|
console.error('Error fetching audio:', error);
|
||||||
|
|
||||||
return new NextResponse(JSON.stringify({ error: 'Internal server error' }), {
|
return new NextResponse(
|
||||||
status: 500,
|
JSON.stringify({ error: 'Internal server error' }),
|
||||||
headers: {
|
{
|
||||||
'Content-Type': 'application/json',
|
status: 500,
|
||||||
...corsHeaders
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
...corsHeaders
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return new NextResponse('Method Not Allowed', {
|
return new NextResponse('Method Not Allowed', {
|
||||||
@ -51,4 +56,4 @@ export async function OPTIONS(request: Request) {
|
|||||||
status: 200,
|
status: 200,
|
||||||
headers: corsHeaders
|
headers: corsHeaders
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -307,6 +307,15 @@
|
|||||||
"schema": {
|
"schema": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"in": "query",
|
||||||
|
"name": "page",
|
||||||
|
"description": "Page number",
|
||||||
|
"required": false,
|
||||||
|
"schema": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
import axios, { AxiosInstance } from 'axios';
|
import axios, { AxiosInstance } from 'axios';
|
||||||
import UserAgent from 'user-agents';
|
import UserAgent from 'user-agents';
|
||||||
import pino from 'pino';
|
import pino from 'pino';
|
||||||
import { wrapper } from "axios-cookiejar-support";
|
import { wrapper } from 'axios-cookiejar-support';
|
||||||
import { CookieJar } from "tough-cookie";
|
import { CookieJar } from 'tough-cookie';
|
||||||
import { sleep } from "@/lib/utils";
|
import { sleep } from '@/lib/utils';
|
||||||
|
|
||||||
const logger = pino();
|
const logger = pino();
|
||||||
export const DEFAULT_MODEL = "chirp-v3-5";
|
export const DEFAULT_MODEL = 'chirp-v3-5';
|
||||||
|
|
||||||
|
|
||||||
export interface AudioInfo {
|
export interface AudioInfo {
|
||||||
id: string; // Unique identifier for the audio
|
id: string; // Unique identifier for the audio
|
||||||
@ -19,7 +18,7 @@ export interface AudioInfo {
|
|||||||
created_at: string; // Date and time when the audio was created
|
created_at: string; // Date and time when the audio was created
|
||||||
model_name: string; // Name of the model used for audio generation
|
model_name: string; // Name of the model used for audio generation
|
||||||
gpt_description_prompt?: string; // Prompt for GPT description
|
gpt_description_prompt?: string; // Prompt for GPT description
|
||||||
prompt?: string; // Prompt for audio generation
|
prompt?: string; // Prompt for audio generation
|
||||||
status: string; // Status
|
status: string; // Status
|
||||||
type?: string;
|
type?: string;
|
||||||
tags?: string; // Genre of music.
|
tags?: string; // Genre of music.
|
||||||
@ -41,16 +40,19 @@ class SunoApi {
|
|||||||
constructor(cookie: string) {
|
constructor(cookie: string) {
|
||||||
const cookieJar = new CookieJar();
|
const cookieJar = new CookieJar();
|
||||||
const randomUserAgent = new UserAgent(/Chrome/).random().toString();
|
const randomUserAgent = new UserAgent(/Chrome/).random().toString();
|
||||||
this.client = wrapper(axios.create({
|
this.client = wrapper(
|
||||||
jar: cookieJar,
|
axios.create({
|
||||||
withCredentials: true,
|
jar: cookieJar,
|
||||||
headers: {
|
withCredentials: true,
|
||||||
'User-Agent': randomUserAgent,
|
headers: {
|
||||||
'Cookie': cookie
|
'User-Agent': randomUserAgent,
|
||||||
}
|
Cookie: cookie
|
||||||
}))
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
this.client.interceptors.request.use((config) => {
|
this.client.interceptors.request.use((config) => {
|
||||||
if (this.currentToken) { // Use the current token status
|
if (this.currentToken) {
|
||||||
|
// Use the current token status
|
||||||
config.headers['Authorization'] = `Bearer ${this.currentToken}`;
|
config.headers['Authorization'] = `Bearer ${this.currentToken}`;
|
||||||
}
|
}
|
||||||
return config;
|
return config;
|
||||||
@ -69,11 +71,13 @@ class SunoApi {
|
|||||||
*/
|
*/
|
||||||
private async getClerkLatestVersion() {
|
private async getClerkLatestVersion() {
|
||||||
// URL to get clerk version ID
|
// URL to get clerk version ID
|
||||||
const getClerkVersionUrl = `${SunoApi.JSDELIVR_BASE_URL}/v1/package/npm/@clerk/clerk-js`;
|
const getClerkVersionUrl = `${SunoApi.JSDELIVR_BASE_URL}/v1/package/npm/@clerk/clerk-js`;
|
||||||
// Get clerk version ID
|
// Get clerk version ID
|
||||||
const versionListResponse = await this.client.get(getClerkVersionUrl);
|
const versionListResponse = await this.client.get(getClerkVersionUrl);
|
||||||
if (!versionListResponse?.data?.['tags']['latest']) {
|
if (!versionListResponse?.data?.['tags']['latest']) {
|
||||||
throw new Error("Failed to get clerk version info, Please try again later");
|
throw new Error(
|
||||||
|
'Failed to get clerk version info, Please try again later'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
// Save clerk version ID for auth
|
// Save clerk version ID for auth
|
||||||
this.clerkVersion = versionListResponse?.data?.['tags']['latest'];
|
this.clerkVersion = versionListResponse?.data?.['tags']['latest'];
|
||||||
@ -84,11 +88,13 @@ class SunoApi {
|
|||||||
*/
|
*/
|
||||||
private async getAuthToken() {
|
private async getAuthToken() {
|
||||||
// URL to get session ID
|
// URL to get session ID
|
||||||
const getSessionUrl = `${SunoApi.CLERK_BASE_URL}/v1/client?_clerk_js_version=${this.clerkVersion}`;
|
const getSessionUrl = `${SunoApi.CLERK_BASE_URL}/v1/client?_clerk_js_version=${this.clerkVersion}`;
|
||||||
// Get session ID
|
// Get session ID
|
||||||
const sessionResponse = await this.client.get(getSessionUrl);
|
const sessionResponse = await this.client.get(getSessionUrl);
|
||||||
if (!sessionResponse?.data?.response?.['last_active_session_id']) {
|
if (!sessionResponse?.data?.response?.['last_active_session_id']) {
|
||||||
throw new Error("Failed to get session id, you may need to update the SUNO_COOKIE");
|
throw new Error(
|
||||||
|
'Failed to get session id, you may need to update the SUNO_COOKIE'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
// Save session ID for later use
|
// Save session ID for later use
|
||||||
this.sid = sessionResponse.data.response['last_active_session_id'];
|
this.sid = sessionResponse.data.response['last_active_session_id'];
|
||||||
@ -100,13 +106,13 @@ class SunoApi {
|
|||||||
*/
|
*/
|
||||||
public async keepAlive(isWait?: boolean): Promise<void> {
|
public async keepAlive(isWait?: boolean): Promise<void> {
|
||||||
if (!this.sid) {
|
if (!this.sid) {
|
||||||
throw new Error("Session ID is not set. Cannot renew token.");
|
throw new Error('Session ID is not set. Cannot renew token.');
|
||||||
}
|
}
|
||||||
// URL to renew session token
|
// URL to renew session token
|
||||||
const renewUrl = `${SunoApi.CLERK_BASE_URL}/v1/client/sessions/${this.sid}/tokens?_clerk_js_version==${this.clerkVersion}`;
|
const renewUrl = `${SunoApi.CLERK_BASE_URL}/v1/client/sessions/${this.sid}/tokens?_clerk_js_version==${this.clerkVersion}`;
|
||||||
// Renew session token
|
// Renew session token
|
||||||
const renewResponse = await this.client.post(renewUrl);
|
const renewResponse = await this.client.post(renewUrl);
|
||||||
logger.info("KeepAlive...\n");
|
logger.info('KeepAlive...\n');
|
||||||
if (isWait) {
|
if (isWait) {
|
||||||
await sleep(1, 2);
|
await sleep(1, 2);
|
||||||
}
|
}
|
||||||
@ -120,21 +126,28 @@ class SunoApi {
|
|||||||
* @param prompt The text prompt to generate audio from.
|
* @param prompt The text prompt to generate audio from.
|
||||||
* @param make_instrumental Indicates if the generated audio should be instrumental.
|
* @param make_instrumental Indicates if the generated audio should be instrumental.
|
||||||
* @param wait_audio Indicates if the method should wait for the audio file to be fully generated before returning.
|
* @param wait_audio Indicates if the method should wait for the audio file to be fully generated before returning.
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
public async generate(
|
public async generate(
|
||||||
prompt: string,
|
prompt: string,
|
||||||
make_instrumental: boolean = false,
|
make_instrumental: boolean = false,
|
||||||
model?: string,
|
model?: string,
|
||||||
wait_audio: boolean = false,
|
wait_audio: boolean = false
|
||||||
|
|
||||||
): Promise<AudioInfo[]> {
|
): Promise<AudioInfo[]> {
|
||||||
await this.keepAlive(false);
|
await this.keepAlive(false);
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
const audios = this.generateSongs(prompt, false, undefined, undefined, make_instrumental, model, wait_audio);
|
const audios = this.generateSongs(
|
||||||
|
prompt,
|
||||||
|
false,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
make_instrumental,
|
||||||
|
model,
|
||||||
|
wait_audio
|
||||||
|
);
|
||||||
const costTime = Date.now() - startTime;
|
const costTime = Date.now() - startTime;
|
||||||
logger.info("Generate Response:\n" + JSON.stringify(audios, null, 2));
|
logger.info('Generate Response:\n' + JSON.stringify(audios, null, 2));
|
||||||
logger.info("Cost time: " + costTime);
|
logger.info('Cost time: ' + costTime);
|
||||||
return audios;
|
return audios;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,11 +165,11 @@ class SunoApi {
|
|||||||
`${SunoApi.BASE_URL}/api/generate/concat/v2/`,
|
`${SunoApi.BASE_URL}/api/generate/concat/v2/`,
|
||||||
payload,
|
payload,
|
||||||
{
|
{
|
||||||
timeout: 10000, // 10 seconds timeout
|
timeout: 10000 // 10 seconds timeout
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
if (response.status !== 200) {
|
if (response.status !== 200) {
|
||||||
throw new Error("Error response:" + response.statusText);
|
throw new Error('Error response:' + response.statusText);
|
||||||
}
|
}
|
||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
@ -172,22 +185,33 @@ class SunoApi {
|
|||||||
* @param negative_tags Negative tags that should not be included in the generated audio.
|
* @param negative_tags Negative tags that should not be included in the generated audio.
|
||||||
* @returns A promise that resolves to an array of AudioInfo objects representing the generated audios.
|
* @returns A promise that resolves to an array of AudioInfo objects representing the generated audios.
|
||||||
*/
|
*/
|
||||||
public async custom_generate(
|
public async custom_generate(
|
||||||
prompt: string,
|
prompt: string,
|
||||||
tags: string,
|
tags: string,
|
||||||
title: string,
|
title: string,
|
||||||
make_instrumental: boolean = false,
|
make_instrumental: boolean = false,
|
||||||
model?: string,
|
model?: string,
|
||||||
wait_audio: boolean = false,
|
wait_audio: boolean = false,
|
||||||
negative_tags?: string,
|
negative_tags?: string
|
||||||
): Promise<AudioInfo[]> {
|
): Promise<AudioInfo[]> {
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
const audios = await this.generateSongs(prompt, true, tags, title, make_instrumental, model, wait_audio, negative_tags);
|
const audios = await this.generateSongs(
|
||||||
const costTime = Date.now() - startTime;
|
prompt,
|
||||||
logger.info("Custom Generate Response:\n" + JSON.stringify(audios, null, 2));
|
true,
|
||||||
logger.info("Cost time: " + costTime);
|
tags,
|
||||||
return audios;
|
title,
|
||||||
}
|
make_instrumental,
|
||||||
|
model,
|
||||||
|
wait_audio,
|
||||||
|
negative_tags
|
||||||
|
);
|
||||||
|
const costTime = Date.now() - startTime;
|
||||||
|
logger.info(
|
||||||
|
'Custom Generate Response:\n' + JSON.stringify(audios, null, 2)
|
||||||
|
);
|
||||||
|
logger.info('Cost time: ' + costTime);
|
||||||
|
return audios;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates songs based on the provided parameters.
|
* Generates songs based on the provided parameters.
|
||||||
@ -209,13 +233,13 @@ public async custom_generate(
|
|||||||
make_instrumental?: boolean,
|
make_instrumental?: boolean,
|
||||||
model?: string,
|
model?: string,
|
||||||
wait_audio: boolean = false,
|
wait_audio: boolean = false,
|
||||||
negative_tags?: string,
|
negative_tags?: string
|
||||||
): Promise<AudioInfo[]> {
|
): Promise<AudioInfo[]> {
|
||||||
await this.keepAlive(false);
|
await this.keepAlive(false);
|
||||||
const payload: any = {
|
const payload: any = {
|
||||||
make_instrumental: make_instrumental == true,
|
make_instrumental: make_instrumental == true,
|
||||||
mv: model || DEFAULT_MODEL,
|
mv: model || DEFAULT_MODEL,
|
||||||
prompt: "",
|
prompt: ''
|
||||||
};
|
};
|
||||||
if (isCustom) {
|
if (isCustom) {
|
||||||
payload.tags = tags;
|
payload.tags = tags;
|
||||||
@ -225,26 +249,35 @@ public async custom_generate(
|
|||||||
} else {
|
} else {
|
||||||
payload.gpt_description_prompt = prompt;
|
payload.gpt_description_prompt = prompt;
|
||||||
}
|
}
|
||||||
logger.info("generateSongs payload:\n" + JSON.stringify({
|
logger.info(
|
||||||
prompt: prompt,
|
'generateSongs payload:\n' +
|
||||||
isCustom: isCustom,
|
JSON.stringify(
|
||||||
tags: tags,
|
{
|
||||||
title: title,
|
prompt: prompt,
|
||||||
make_instrumental: make_instrumental,
|
isCustom: isCustom,
|
||||||
wait_audio: wait_audio,
|
tags: tags,
|
||||||
negative_tags: negative_tags,
|
title: title,
|
||||||
payload: payload,
|
make_instrumental: make_instrumental,
|
||||||
}, null, 2));
|
wait_audio: wait_audio,
|
||||||
|
negative_tags: negative_tags,
|
||||||
|
payload: payload
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
2
|
||||||
|
)
|
||||||
|
);
|
||||||
const response = await this.client.post(
|
const response = await this.client.post(
|
||||||
`${SunoApi.BASE_URL}/api/generate/v2/`,
|
`${SunoApi.BASE_URL}/api/generate/v2/`,
|
||||||
payload,
|
payload,
|
||||||
{
|
{
|
||||||
timeout: 10000, // 10 seconds timeout
|
timeout: 10000 // 10 seconds timeout
|
||||||
},
|
}
|
||||||
|
);
|
||||||
|
logger.info(
|
||||||
|
'generateSongs Response:\n' + JSON.stringify(response.data, null, 2)
|
||||||
);
|
);
|
||||||
logger.info("generateSongs Response:\n" + JSON.stringify(response.data, null, 2));
|
|
||||||
if (response.status !== 200) {
|
if (response.status !== 200) {
|
||||||
throw new Error("Error response:" + response.statusText);
|
throw new Error('Error response:' + response.statusText);
|
||||||
}
|
}
|
||||||
const songIds = response.data['clips'].map((audio: any) => audio.id);
|
const songIds = response.data['clips'].map((audio: any) => audio.id);
|
||||||
//Want to wait for music file generation
|
//Want to wait for music file generation
|
||||||
@ -255,11 +288,9 @@ public async custom_generate(
|
|||||||
while (Date.now() - startTime < 100000) {
|
while (Date.now() - startTime < 100000) {
|
||||||
const response = await this.get(songIds);
|
const response = await this.get(songIds);
|
||||||
const allCompleted = response.every(
|
const allCompleted = response.every(
|
||||||
audio => audio.status === 'streaming' || audio.status === 'complete'
|
(audio) => audio.status === 'streaming' || audio.status === 'complete'
|
||||||
);
|
|
||||||
const allError = response.every(
|
|
||||||
audio => audio.status === 'error'
|
|
||||||
);
|
);
|
||||||
|
const allError = response.every((audio) => audio.status === 'error');
|
||||||
if (allCompleted || allError) {
|
if (allCompleted || allError) {
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
@ -285,7 +316,7 @@ public async custom_generate(
|
|||||||
type: audio.metadata.type,
|
type: audio.metadata.type,
|
||||||
tags: audio.metadata.tags,
|
tags: audio.metadata.tags,
|
||||||
negative_tags: audio.metadata.negative_tags,
|
negative_tags: audio.metadata.negative_tags,
|
||||||
duration: audio.metadata.duration,
|
duration: audio.metadata.duration
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -298,14 +329,21 @@ public async custom_generate(
|
|||||||
public async generateLyrics(prompt: string): Promise<string> {
|
public async generateLyrics(prompt: string): Promise<string> {
|
||||||
await this.keepAlive(false);
|
await this.keepAlive(false);
|
||||||
// Initiate lyrics generation
|
// Initiate lyrics generation
|
||||||
const generateResponse = await this.client.post(`${SunoApi.BASE_URL}/api/generate/lyrics/`, { prompt });
|
const generateResponse = await this.client.post(
|
||||||
|
`${SunoApi.BASE_URL}/api/generate/lyrics/`,
|
||||||
|
{ prompt }
|
||||||
|
);
|
||||||
const generateId = generateResponse.data.id;
|
const generateId = generateResponse.data.id;
|
||||||
|
|
||||||
// Poll for lyrics completion
|
// Poll for lyrics completion
|
||||||
let lyricsResponse = await this.client.get(`${SunoApi.BASE_URL}/api/generate/lyrics/${generateId}`);
|
let lyricsResponse = await this.client.get(
|
||||||
|
`${SunoApi.BASE_URL}/api/generate/lyrics/${generateId}`
|
||||||
|
);
|
||||||
while (lyricsResponse?.data?.status !== 'complete') {
|
while (lyricsResponse?.data?.status !== 'complete') {
|
||||||
await sleep(2); // Wait for 2 seconds before polling again
|
await sleep(2); // Wait for 2 seconds before polling again
|
||||||
lyricsResponse = await this.client.get(`${SunoApi.BASE_URL}/api/generate/lyrics/${generateId}`);
|
lyricsResponse = await this.client.get(
|
||||||
|
`${SunoApi.BASE_URL}/api/generate/lyrics/${generateId}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the generated lyrics text
|
// Return the generated lyrics text
|
||||||
@ -314,7 +352,7 @@ public async custom_generate(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Extends an existing audio clip by generating additional content based on the provided prompt.
|
* Extends an existing audio clip by generating additional content based on the provided prompt.
|
||||||
*
|
*
|
||||||
* @param audioId The ID of the audio clip to extend.
|
* @param audioId The ID of the audio clip to extend.
|
||||||
* @param prompt The prompt for generating additional content.
|
* @param prompt The prompt for generating additional content.
|
||||||
* @param continueAt Extend a new clip from a song at mm:ss(e.g. 00:30). Default extends from the end of the song.
|
* @param continueAt Extend a new clip from a song at mm:ss(e.g. 00:30). Default extends from the end of the song.
|
||||||
@ -324,21 +362,24 @@ public async custom_generate(
|
|||||||
*/
|
*/
|
||||||
public async extendAudio(
|
public async extendAudio(
|
||||||
audioId: string,
|
audioId: string,
|
||||||
prompt: string = "",
|
prompt: string = '',
|
||||||
continueAt: string = "0",
|
continueAt: string = '0',
|
||||||
tags: string = "",
|
tags: string = '',
|
||||||
title: string = "",
|
title: string = '',
|
||||||
model?: string,
|
model?: string
|
||||||
): Promise<AudioInfo> {
|
): Promise<AudioInfo> {
|
||||||
const response = await this.client.post(`${SunoApi.BASE_URL}/api/generate/v2/`, {
|
const response = await this.client.post(
|
||||||
continue_clip_id: audioId,
|
`${SunoApi.BASE_URL}/api/generate/v2/`,
|
||||||
continue_at: continueAt,
|
{
|
||||||
mv: model || DEFAULT_MODEL,
|
continue_clip_id: audioId,
|
||||||
prompt: prompt,
|
continue_at: continueAt,
|
||||||
tags: tags,
|
mv: model || DEFAULT_MODEL,
|
||||||
title: title
|
prompt: prompt,
|
||||||
});
|
tags: tags,
|
||||||
console.log("response:\n", response);
|
title: title
|
||||||
|
}
|
||||||
|
);
|
||||||
|
console.log('response:\n', response);
|
||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -354,7 +395,7 @@ public async custom_generate(
|
|||||||
// The following implementation assumes that the lyrics are already separated by newlines.
|
// The following implementation assumes that the lyrics are already separated by newlines.
|
||||||
|
|
||||||
// Split the lyrics using newline and ensure to remove empty lines.
|
// Split the lyrics using newline and ensure to remove empty lines.
|
||||||
const lines = prompt.split('\n').filter(line => line.trim() !== '');
|
const lines = prompt.split('\n').filter((line) => line.trim() !== '');
|
||||||
|
|
||||||
// Reassemble the processed lyrics lines into a single string, separated by newlines between each line.
|
// Reassemble the processed lyrics lines into a single string, separated by newlines between each line.
|
||||||
// Additional formatting logic can be added here, such as adding specific markers or handling special lines.
|
// Additional formatting logic can be added here, such as adding specific markers or handling special lines.
|
||||||
@ -364,26 +405,36 @@ public async custom_generate(
|
|||||||
/**
|
/**
|
||||||
* Retrieves audio information for the given song IDs.
|
* Retrieves audio information for the given song IDs.
|
||||||
* @param songIds An optional array of song IDs to retrieve information for.
|
* @param songIds An optional array of song IDs to retrieve information for.
|
||||||
|
* @param page An optional page number to retrieve audio information from.
|
||||||
* @returns A promise that resolves to an array of AudioInfo objects.
|
* @returns A promise that resolves to an array of AudioInfo objects.
|
||||||
*/
|
*/
|
||||||
public async get(songIds?: string[]): Promise<AudioInfo[]> {
|
public async get(
|
||||||
|
songIds?: string[],
|
||||||
|
page?: string | null
|
||||||
|
): Promise<AudioInfo[]> {
|
||||||
await this.keepAlive(false);
|
await this.keepAlive(false);
|
||||||
let url = `${SunoApi.BASE_URL}/api/feed/`;
|
let url = new URL(`${SunoApi.BASE_URL}/api/feed/`);
|
||||||
if (songIds) {
|
if (songIds) {
|
||||||
url = `${url}?ids=${songIds.join(',')}`;
|
url.searchParams.append('ids', songIds.join(','));
|
||||||
}
|
}
|
||||||
logger.info("Get audio status: " + url);
|
if (page) {
|
||||||
const response = await this.client.get(url, {
|
url.searchParams.append('page', page);
|
||||||
|
}
|
||||||
|
logger.info('Get audio status: ' + url.href);
|
||||||
|
const response = await this.client.get(url.href, {
|
||||||
// 3 seconds timeout
|
// 3 seconds timeout
|
||||||
timeout: 3000
|
timeout: 3000
|
||||||
});
|
});
|
||||||
|
|
||||||
const audios = response.data;
|
const audios = response.data;
|
||||||
|
|
||||||
return audios.map((audio: any) => ({
|
return audios.map((audio: any) => ({
|
||||||
id: audio.id,
|
id: audio.id,
|
||||||
title: audio.title,
|
title: audio.title,
|
||||||
image_url: audio.image_url,
|
image_url: audio.image_url,
|
||||||
lyric: audio.metadata.prompt ? this.parseLyrics(audio.metadata.prompt) : "",
|
lyric: audio.metadata.prompt
|
||||||
|
? this.parseLyrics(audio.metadata.prompt)
|
||||||
|
: '',
|
||||||
audio_url: audio.audio_url,
|
audio_url: audio.audio_url,
|
||||||
video_url: audio.video_url,
|
video_url: audio.video_url,
|
||||||
created_at: audio.created_at,
|
created_at: audio.created_at,
|
||||||
@ -393,8 +444,8 @@ public async custom_generate(
|
|||||||
prompt: audio.metadata.prompt,
|
prompt: audio.metadata.prompt,
|
||||||
type: audio.metadata.type,
|
type: audio.metadata.type,
|
||||||
tags: audio.metadata.tags,
|
tags: audio.metadata.tags,
|
||||||
duration: audio.metadata.duration,
|
duration: audio.metadata.duration,
|
||||||
error_message: audio.metadata.error_message,
|
error_message: audio.metadata.error_message
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -405,18 +456,22 @@ public async custom_generate(
|
|||||||
*/
|
*/
|
||||||
public async getClip(clipId: string): Promise<object> {
|
public async getClip(clipId: string): Promise<object> {
|
||||||
await this.keepAlive(false);
|
await this.keepAlive(false);
|
||||||
const response = await this.client.get(`${SunoApi.BASE_URL}/api/clip/${clipId}`);
|
const response = await this.client.get(
|
||||||
|
`${SunoApi.BASE_URL}/api/clip/${clipId}`
|
||||||
|
);
|
||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async get_credits(): Promise<object> {
|
public async get_credits(): Promise<object> {
|
||||||
await this.keepAlive(false);
|
await this.keepAlive(false);
|
||||||
const response = await this.client.get(`${SunoApi.BASE_URL}/api/billing/info/`);
|
const response = await this.client.get(
|
||||||
|
`${SunoApi.BASE_URL}/api/billing/info/`
|
||||||
|
);
|
||||||
return {
|
return {
|
||||||
credits_left: response.data.total_credits_left,
|
credits_left: response.data.total_credits_left,
|
||||||
period: response.data.period,
|
period: response.data.period,
|
||||||
monthly_limit: response.data.monthly_limit,
|
monthly_limit: response.data.monthly_limit,
|
||||||
monthly_usage: response.data.monthly_usage,
|
monthly_usage: response.data.monthly_usage
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -424,10 +479,10 @@ public async custom_generate(
|
|||||||
const newSunoApi = async (cookie: string) => {
|
const newSunoApi = async (cookie: string) => {
|
||||||
const sunoApi = new SunoApi(cookie);
|
const sunoApi = new SunoApi(cookie);
|
||||||
return await sunoApi.init();
|
return await sunoApi.init();
|
||||||
}
|
};
|
||||||
|
|
||||||
if (!process.env.SUNO_COOKIE) {
|
if (!process.env.SUNO_COOKIE) {
|
||||||
console.log("Environment does not contain SUNO_COOKIE.", process.env)
|
console.log('Environment does not contain SUNO_COOKIE.', process.env);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const sunoApi = newSunoApi(process.env.SUNO_COOKIE || '');
|
export const sunoApi = newSunoApi(process.env.SUNO_COOKIE || '');
|
||||||
|
Loading…
Reference in New Issue
Block a user