> ## Documentation Index
> Fetch the complete documentation index at: https://docs.youka.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Projects

> Tải lên media và tạo, kiểm tra, liệt kê, và xóa các dự án karaoke

Projects là tài nguyên cấp cao nhất trong Youka. Mỗi project sở hữu tệp nguồn, các stem đã tách, lời bài hát đã đồng bộ, các bản xuất, và cài đặt project.

## Tạo một project

Trong hầu hết trường hợp, hãy dùng `client.projects.create()` — hàm này sẽ tự xử lý việc tải lên cho bạn.

```ts theme={null}
const operation = await client.projects.create({
  source: { type: "path", path: "./song.mp3" },
  lyricsSource: { type: "transcribe" },
});
// => ProjectOperation
```

### Các loại source

<Tabs>
  <Tab title="path">
    Đọc một tệp từ ổ đĩa.

    ```ts theme={null}
    source: {
      type: "path",
      path: "./song.mp3",
      contentType: "audio/mpeg", // optional, inferred if omitted
    }
    ```
  </Tab>

  <Tab title="bytes">
    `Blob`, `File`, `ArrayBuffer`, hoặc `Uint8Array` trong bộ nhớ.

    ```ts theme={null}
    source: {
      type: "bytes",
      data: fileBuffer,
      filename: "song.mp3",
      contentType: "audio/mpeg", // optional
    }
    ```
  </Tab>

  <Tab title="url">
    URL HTTP hoặc HTTPS từ xa.

    Các trang được hỗ trợ phụ thuộc vào yt-dlp. Xem [danh sách URL được hỗ trợ](https://github.com/yt-dlp/yt-dlp/blob/master/supportedsites.md).

    ```ts theme={null}
    source: {
      type: "url",
      url: "https://example.com/song.mp4",
      maxVideoQuality: "1080p", // optional: "720p", "1080p", "4k", or "best"
    }
    ```

    `maxVideoQuality` điều khiển chất lượng video tối đa được tải xuống cho các source
    dạng URL. Mặc định là `1080p`. SDK sẽ dùng chất lượng tốt nhất hiện có
    trong giới hạn đó, và sẽ rơi về định dạng tốt nhất hiện có nếu nền tảng
    không cung cấp luồng có giới hạn. Dùng `best` để không giới hạn.

    <Note>
      Trên Node.js và Bun, SDK sẽ tự động đảm bảo các binary phụ thuộc cần thiết cho URL
      (`ffmpeg`, `ffprobe`, `yt-dlp`) ngay lần sử dụng đầu tiên. Lệnh CLI tương đương là `youka deps ensure --for url`.
    </Note>
  </Tab>
</Tabs>

### Các trường khác

<ParamField path="title" type="string">
  Tiêu đề project. Mặc định là tên tệp nguồn.
</ParamField>

<ParamField path="splitModel" type="SplitModel">
  Mô hình tách stem. Mặc định là `mdx23c`. Xem [tài liệu tham chiếu Split model
  reference](/vi/desktop/split-model).
</ParamField>

<ParamField path="presetId" type="string">
  Áp dụng một preset có thể tái sử dụng tại thời điểm tạo.
</ParamField>

<ParamField path="lyricsSource" type="LyricsSource">
  Cấu hình đồng bộ lời bài hát. Xem bên dưới.
</ParamField>

### Các nguồn lyrics

```ts theme={null}
// Transcribe lyrics from the audio
lyricsSource: {
  type: "transcribe",
  syncModel: "audioshake-transcription", // optional
  language: "en",                        // optional
}

// Align exact lyrics to the audio
lyricsSource: {
  type: "align",
  lyrics: "First line\nSecond line\n...",
  syncModel: "audioshake-alignment",
}

```

## `client.projects.create(input, options?)`

`client.projects.create()` cũng chấp nhận source `inputFile` cấp thấp khi bạn đã có `inputFileId` được tải lên.

```ts theme={null}
const upload = await client.uploads.create({
  filename: "song.mp3",
  contentType: "audio/mpeg",
  contentLength: buffer.byteLength,
});

await client.uploads.upload(upload.uploadUrl, buffer, {
  contentType: "audio/mpeg",
});

const operation = await client.projects.create({
  source: {
    type: "inputFile",
    inputFileId: upload.inputFileId,
    filename: "song.mp3",
  },
  title: "My Song",
});
```

## `client.projects.quote(input, options?)`

Báo giá số credits cần để tạo một project mà không tạo project đó.

```ts theme={null}
const quote = await client.projects.quote({
  source: { type: "path", path: "./song.mp3" },
  lyricsSource: { type: "transcribe", language: "en" },
  splitModel: "mdx23c",
});

console.log(quote.creditsRequired, quote.sufficientBalance);
```

`client.projects.quote(...)` chấp nhận cùng các dạng `source` như
`client.projects.create(...)`, bao gồm URL `maxVideoQuality`. Nếu bạn đã
biết thời lượng media và không muốn tải tệp lên chỉ để báo giá, hãy truyền
dạng REST cấp thấp:

```ts theme={null}
const quote = await client.projects.quote({
  durationSeconds: 210,
  lyricsSource: null,
  splitModel: "mdx23c",
});
```

## `client.uploads.create(body, options?)`

Cấp phát một slot tải lên và nhận một URL đã ký.

```ts theme={null}
const upload = await client.uploads.create({
  filename: "song.mp3",
  contentType: "audio/mpeg",
  contentLength: 4_521_344,
});
// => { inputFileId, uploadUrl }
```

## `client.uploads.upload(uploadUrl, body, options?)`

PUT các byte của tệp lên URL đã ký.

```ts theme={null}
await client.uploads.upload(upload.uploadUrl, fileBuffer, {
  contentType: "audio/mpeg",
  signal: abortController.signal,
});
```

<ParamField path="body" type="FetchBody" required>
  Bất kỳ body tương thích với `fetch`: `Blob`, `File`, `ArrayBuffer`, `Uint8Array`,
  `ReadableStream`, hoặc `string`.
</ParamField>

Ném `YoukaRequestError` với mã `UPLOAD_FAILED` nếu thao tác tải lên trả về trạng thái không thuộc 2xx.

## `client.projects.get(projectId, options?)`

Lấy trạng thái đầy đủ của project, bao gồm stems, lyrics, và exports.

```ts theme={null}
const project = await client.projects.get("prj_abc123");
console.log(project.title, project.stems, project.lyrics);
```

## `client.projects.update(projectId, body, options?)`

Patch metadata của project.

```ts theme={null}
const project = await client.projects.update("prj_abc123", {
  title: "Updated title",
  artists: ["Artist name"],
});
```

Hãy truyền ít nhất một trong `title` hoặc `artists`.

## `client.projects.list(options?)`

Liệt kê mọi project thuộc về tài khoản đã xác thực.

```ts theme={null}
const projects = await client.projects.list();
projects.forEach((p) => console.log(p.id, p.title));
```

Trả về một mảng các project list item (một dạng gọn hơn so với `getProject`).

## `client.projects.delete(projectId, options?)`

Xóa một project và tất cả stems, lyrics, và exports liên quan.

```ts theme={null}
await client.projects.delete("prj_abc123", {
  idempotencyKey: "delete-prj_abc123",
});
```

<Warning>
  Việc xóa là vĩnh viễn. Hãy kết hợp với một idempotency key để việc thử lại được an toàn.
</Warning>

## Tiếp theo

* [Stems](/vi/sdk/stems) — chạy lại tách stem
* [Lyrics sync](/vi/sdk/lyrics-sync) — đồng bộ lại lyrics
* [Exports](/vi/sdk/exports) — render video hoàn chỉnh
* [Tasks](/vi/sdk/tasks) — chờ các thao tác project với `client.projects.wait`
