# Technical Documentation: Chocobozzz/PeerTube

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/Chocobozzz/PeerTube)

### Overview (`README.md`)

<h1 align="center">
  <a href="https://joinpeertube.org">
    <img src="https://joinpeertube.org/img/brand.png" alt="PeerTube">
  </a>
</h1>

<p align=center>
  <strong><a href="https://joinpeertube.org">Website</a></strong>
  | <strong><a href="https://joinpeertube.org/instances">Join an instance</a></strong>
  | <strong><a href="https://github.com/Chocobozzz/PeerTube/blob/develop/README.md#package-create-your-own-instance">Create an instance</a></strong>
  | <strong><a href="https://github.com/Chocobozzz/PeerTube/blob/develop/README.md#contact">Chat with us</a></strong>
  | <strong><a href="https://framasoft.org/en/#soutenir">Donate</a></strong>
</p>

<p align="center">
Be part of a network of multiple small federated, interoperable video hosting providers. Follow video creators and create videos. No vendor lock-in. All on a platform that is community-owned and ad-free.
</p>

<p align="center">
  <strong>Developed with &#10084; by <a href="https://framasoft.org">Framasoft</a></strong>
</p>

<p align="center">
  <a href="https://framasoft.org">
    <img width="150px" src="https://asso.framasoft.org/pic/7dcsknbA/8XSBIpLF.png" alt="Framasoft logo"/>
  </a>
</p>

<div align="center">
  <a href="https://github.com/Chocobozzz/PeerTube/actions?query=workflow%3A%22Test%22+branch%3Adevelop">
    <img src="https://github.com/Chocobozzz/PeerTube/workflows/Test/badge.svg" alt="GitHub Test Status">
  </a>

  <a href="https://automate.browserstack.com/public-build/d0ZMeGpSUFRjaUpDNnN3NUdKY1l2TnNpTGVJaUI0bm9hYkNxMTRtQ1lHTT0tLVZQa2crbFB1c2RDZUl1Y1Blck02SFE9PQ==--5f956d6857c50e06a0b7b1fe405fb93d0f2d0e11%">
    <img src="https://automate.browserstack.com/badge.svg?badge_key=d0ZMeGpSUFRjaUpDNnN3NUdKY1l2TnNpTGVJaUI0bm9hYkNxMTRtQ1lHTT0tLVZQa2crbFB1c2RDZUl1Y1Blck02SFE9PQ==--5f956d6857c50e06a0b7b1fe405fb93d0f2d0e11%" alt="BrowserStack Status">
  </a>

  <a href="https://weblate.framasoft.org/projects/peertube/angular/">
    <img src="https://weblate.framasoft.org/widgets/peertube/-/angular/svg-badge.svg" alt="Weblate Status">
  </a>

  <a href="https://digitalpublicgoods.net/r/peertube"><img src="https://img.shields.io/badge/Verified-DPG-3333AB?logo=data:image/svg%2bxml;base64,PHN2ZyB3aWR0aD0iMzEiIGhlaWdodD0iMzMiIHZpZXdCb3g9IjAgMCAzMSAzMyIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTE0LjIwMDggMjEuMzY3OEwxMC4xNzM2IDE4LjAxMjRMMTEuNTIxOSAxNi40MDAzTDEzLjk5MjggMTguNDU5TDE5LjYyNjkgMTIuMjExMUwyMS4xOTA5IDEzLjYxNkwxNC4yMDA4IDIxLjM2NzhaTTI0LjYyNDEgOS4zNTEyN0wyNC44MDcxIDMuMDcyOTdMMTguODgxIDUuMTg2NjJMMTUuMzMxNCAtMi4zMzA4MmUtMDVMMTEuNzgyMSA1LjE4NjYyTDUuODU2MDEgMy4wNzI5N0w2LjAzOTA2IDkuMzUxMjdMMCAxMS4xMTc3TDMuODQ1MjEgMTYuMDg5NUwwIDIxLjA2MTJMNi4wMzkwNiAyMi44Mjc3TDUuODU2MDEgMjkuMTA2TDExLjc4MjEgMjYuOTkyM0wxNS4zMzE0IDMyLjE3OUwxOC44ODEgMjYuOTkyM0wyNC44MDcxIDI5LjEwNkwyNC42MjQxIDIyLjgyNzdMMzAuNjYzMSAyMS4wNjEyTDI2LjgxNzYgMTYuMDg5NUwzMC42NjMxIDExLjExNzdMMjQuNjI0MSA5LjM1MTI3WiIgZmlsbD0id2hpdGUiLz4KPC9zdmc+Cg==" alt="DPG Badge"/></a>
</div>

<br />

<p align="center">
  <a href="https://framatube.org/w/kkGMgK9ZtnKfYAgnEtQxbv">
    <img src="https://asso.framasoft.org/pic/wI6n1YIH/hKfCL8Xi.png" alt="screenshot" />
  </a>
</p>

Introduction
----------------------------------------------------------------

PeerTube is a free, decentralized and federated video platform developed as an alternative to other platforms that centralize our data and attention, such as YouTube, Dailymotion or Vimeo. :clapper:

To learn more:
* This [two-minute video](https://framatube.org/videos/watch/217eefeb-883d-45be-b7fc-a788ad8507d3) (hosted on PeerTube) explaining what PeerTube is and how it works
* PeerTube's project homepage, [joinpeertube.org](https://joinpeertube.org)
* Demonstration instances:
  * [peertube.cpy.re](https://peertube.cpy.re) (stable)
  * [peertube2.cpy.re](https://peertube2.cpy.re) (Nightly)
  * [peertube3.cpy.re](https://peertube3.cpy.re) (RC)
* This [video](https://peertube.cpy.re/videos/watch/da2b08d4-a242-4170-b32a-4ec8cbdca701) demonstrating the communication between PeerTube and [Mastodon](https://github.com/tootsuite/mastodon) (a decentralized Twitter alternative)

:sparkles: Features
----------------------------------------------------------------

<p align=center>
  <strong><a href="https://joinpeertube.org/faq#what-are-the-peertube-features-for-viewers">All features for viewers</a></strong>
  | <strong><a href="https://joinpeertube.org/faq#what-are-the-peertube-features-for-content-creators">All features for content creators</a></strong>
  | <strong><a href="https://joinpeertube.org/faq#what-are-the-peertube-features-for-administrators">All features for administrators</a></strong>
</p>

<img src="https://asso.framasoft.org/pic/z6py52z2/61ZyIm65.png" align="left" height="300px"/>
<h3 align="left">Video streaming, even in live!</h3>
<p align="left">
Just upload your videos, and be sure they will stream anywhere. Add a description, some tags and your video will be discoverable by the entire video fediverse, not just your instance. You can even embed a player on your favorite website!
</p>
<p align="left">
You are used to hosting live events? We got you covered too! Start livestreaming from your favorite client, and even host permanent streams!
</p>

---

<img src="https://asso.framasoft.org/pic/lYrgaP2N/Sj3hgkeo.png" align="right" height="200px"/>

<h3 align="right">Keep in touch with video creators</h3>
<p align="right">
Follow your favorite channels from PeerTube or really any other place. No need to have an account on the instance you watched a video to follow its author, you can do all of that from the Fediverse (Mastodon, Pleroma, and plenty others), or just with good ol' RSS.
</p>

---

<img src="https://asso.framasoft.org/pic/UbNnLlzV/Sx0PSrH1.png" align="left" height="200px"/>

<h3 align="left">An interface to call home</h3>
<p align="left">
Be it as a user or an instance administrator, you can decide what your experience will be like. Don't like the colors? They are easy to change. Don't want to list videos of an instance but let your users subscribe to them? Don't like the regular web client? All of that can be changed, and much more. No UX dark pattern, no mining your data, no video recommendation bullshit™.
</p>

---

<h3 align="right">Communities that help each other</h3>
<p align="right">
In addition to visitors using P2P with WebRTC to share the load among them, instances can help each other by caching one another's videos. This way even small instances have a way to show content to a wider audience, as they will be shouldered by friend instances (more about that in our <a href="https://docs.joinpeertube.org/contribute/architecture#redundancy-between-instances">redundancy guide</a>).
</p>
<p align="right">
Content creators can get help from their viewers in the simplest way possible: a support button showing a message linking to their donation accounts or really anything else. No more pay-per-view and advertisements that hurt visitors and alter creativity (more about that in our <a href="https://github.com/Chocobozzz/PeerTube/blob/develop/FAQ.md">FAQ</a>).
</p>



:raised_hands: Contributing
----------------------------------------------------------------

You don't need to be a programmer to help!

You can give us your feedback, report bugs, help us translate PeerTube, write documentation, and more. Check out the [contributing
guide](https://docs.joinpeertube.org/contribute/getting-started) to know how, it takes less than 2 minutes to get started. :wink:

You can also join the cheerful bunch that makes our community<a name="contact"></a>:

* Matrix (bridged on [Discord](https://discord.gg/wj8DDUT)): **[#peertube:matrix.org](https://matrix.to/#/#peertube:matrix.org)**
* Forum: [https://framacolibri.org/c/peertube](https://framacolibri.org/c/peertube)

Feel free to reach out if you have any questions or ideas! :speech_balloon:

:package: Create your own instance
----------------------------------------------------------------

See the [production guide](https://docs.joinpeertube.org/install/any-os), which is the recommended way to install or upgrade PeerTube. For hardware requirements, see [Should I have a big server to run PeerTube?](https://joinpeertube.org/faq#should-i-have-a-big-server-to-run-peertube) in the FAQ.

See the [community packages](https://docs.joinpeertube.org/install/unofficial), which cover various platforms (including [YunoHost](https://install-app.yunohost.org/?app=peertube) and [Docker](https://github.com/Chocobozzz/PeerTube/blob/develop/support/doc/docker.md)).

:book: Documentation
----------------------------------------------------------------

If you have a question, please try to find the answer in the [FAQ](https://joinpeertube.org/faq) first.

### User documentation

See the [user documentation](https://docs.joinpeertube.org/use/setup-account).

### Admin documentation

See [how to create your own instance](https://github.com/Chocobozzz/PeerTube/blob/develop/README.md#package-create-your-own-instance).

See the more general [admin documentation](https://docs.joinpeertube.org/admin/following-instances).

### Tools documentation

Learn how to import/upload videos from CLI or admin your PeerTube instance with the [tools documentation](https://docs.joinpeertube.org/maintain/tools).

### Technical documentation

See the [architecture blueprint](https://docs.joinpeertube.org/contribute/architecture) for a more detailed explanation of the architectural choices.

See our REST API documentation:
  * OpenAPI 3.0.0 schema: [/support/doc/api/openapi.yaml](https://github.com/Chocobozzz/PeerTube/blob/develop/support/doc/api/openapi.yaml)
  * Spec explorer: [docs.joinpeertube.org/api-rest-reference.html](https://docs.joinpeertube.org/api-rest-reference.html)

See our [ActivityPub documentation](https://docs.joinpeertube.org/api/activitypub).

## License

### Logo

[CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/), by [Framasoft](https://framasoft.org)

### Code

Copyright (C) 2015-2025 PeerTube Contributors (see [CREDITS.md](/CREDITS.md))

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.

---

### Overview (`apps/peertube-cli/README.md`)

# PeerTube CLI

## Usage

See https://docs.joinpeertube.org/maintain/tools#remote-tools

## Dev

## Install dependencies

```bash
cd peertube-root
npm run install-node-dependencies
```

## Develop

```bash
cd peertube-root
npm run dev:peertube-cli
```

## Build

```bash
cd peertube-root
npm run build:peertube-cli
```

## Run

```bash
cd peertube-root
node apps/peertube-cli/dist/peertube.js --help
```

## Publish on NPM

```bash
cd peertube-root
(cd apps/peertube-cli && npm version patch) && npm run build:peertube-cli && (cd apps/peertube-cli && npm login && npm publish --access=public)
```

---

### Overview (`apps/peertube-runner/README.md`)

# PeerTube runner

Runner program to execute jobs (transcoding...) of remote PeerTube instances.

Commands below has to be run at the root of PeerTube git repository.

## Dev

### Install dependencies

```bash
cd peertube-root
npm run install-node-dependencies
```

### Develop

```bash
cd peertube-root
npm run dev:peertube-runner
```

### Build

```bash
cd peertube-root
npm run build:peertube-runner
```

### Run

```bash
cd peertube-root
node apps/peertube-runner/dist/peertube-runner.mjs --help
```

### Publish on NPM

```bash
cd peertube-root
(cd apps/peertube-runner && npm version patch) && npm run build:peertube-runner && (cd apps/peertube-runner && npm login && npm publish --access=public)
```

---

### Overview (`packages/transcription-devtools/README.md`)

# Transcription DevTools

Includes:
  * __JiWER__ CLI NodeJS wrapper
  * Benchmark tool to test multiple transcription engines
  * TypeScript classes to evaluate word-error-rate of files generated by the transcription

## Build

```sh
npm run build
```

## Benchmark

A benchmark of available __transcribers__ might be run with:
```sh
npm run benchmark
```
```
┌────────────────────────┬───────────────────────┬───────────────────────┬──────────┬────────┬───────────────────────┐
│        (index)         │          WER          │          CER          │ duration │ model  │        engine         │
├────────────────────────┼───────────────────────┼───────────────────────┼──────────┼────────┼───────────────────────┤
│ 5yZGBYqojXe7nuhq1TuHvz │ '28.39506172839506%'  │  '9.62457337883959%'  │  '41s'   │ 'tiny' │   'openai-whisper'    │
│ x6qREJ2AkTU4e5YmvfivQN │ '29.75206611570248%'  │ '10.46195652173913%'  │  '15s'   │ 'tiny' │ 'whisper-ctranslate2' │
└────────────────────────┴───────────────────────┴───────────────────────┴──────────┴────────┴───────────────────────┘
```

The benchmark may be run with multiple model builtin sizes:

```sh
MODELS=tiny,small,large npm run benchmark
```

## Jiwer

> *JiWER is a python tool for computing the word-error-rate of ASR systems.*
> https://jitsi.github.io/jiwer/cli/

__JiWER__ serves as a reference implementation to calculate errors rates between 2 text files:
- WER (Word Error Rate)
- CER (Character Error Rate)


### Usage

```typescript
const jiwerCLI = new JiwerClI('./reference.txt', './hypothesis.txt')

// WER as a percentage, ex: 0.03 -> 3%
console.log(await jiwerCLI.wer())

// CER as a percentage: 0.01 -> 1%
console.log(await jiwerCLI.cer())

// Detailed comparison report
console.log(await jiwerCLI.alignment())
```

## Resources

- https://jitsi.github.io/jiwer/
- https://github.com/rapidfuzz/RapidFuzz

---

### Overview (`packages/transcription/README.md`)

# Transcription

Video **transcription** consists in transcribing the audio content of a video to a text.

> This process might be called __Automatic Speech Recognition__ or __Speech to Text__ in more general context.

Provide a common API to many transcription backend, currently:
  - `openai-whisper` CLI
  - `faster-whisper` (*via* `whisper-ctranslate2` CLI)

> Potential candidates could be: whisper-cpp, vosk, ...

## Requirements
  - Python 3
  - PIP

And at least one of the following transcription backend:
  - Python:
    - `openai-whisper`
    - `whisper-ctranslate2>=0.4.3`

## Usage

Create a transcriber manually:

```typescript
import { OpenaiTranscriber } from '@peertube/peertube-transcription'

(async () => {
  // Optional if you want to use a local installation of transcribe engines
  const binDirectory = 'local/pip/path/bin'

  // Create a transcriber powered by OpenAI Whisper CLI
  const transcriber = new OpenaiTranscriber({
    name: 'openai-whisper',
    command: 'whisper',
    languageDetection: true,
    binDirectory
  });

  // If not installed globally, install the transcriber engine (use pip under the hood)
  await transcriber.install('local/pip/path')

  // Transcribe
  const transcriptFile = await transcriber.transcribe({
    mediaFilePath: './myVideo.mp4',
    model: 'tiny',
    format: 'txt'
  });

  console.log(transcriptFile.path);
  console.log(await transcriptFile.read());
})();
```

Using a local model file:

```typescript
import { WhisperBuiltinModel } from '@peertube/peertube-transcription/dist'

const transcriptFile = await transcriber.transcribe({
  mediaFilePath: './myVideo.mp4',
  model: await WhisperBuiltinModel.fromPath('./models/large.pt'),
  format: 'txt'
});
```

You may use the builtin Factory if you're happy with the default configuration:

```Typescript
import { transcriberFactory } from '@peertube/peertube-transcription'

transcriberFactory.createFromEngineName({
  engineName: transcriberName,
  logger: compatibleWinstonLogger,
  transcriptDirectory: '/tmp/transcription'
})
```
> For further usage [../tests/src/transcription/whisper/transcriber/openai-transcriber.spec.ts](../tests/src/transcription/whisper/transcriber/openai-transcriber.spec.ts)


## Lexicon
- ONNX: Open Neural Network eXchange. A specification, the ONNX Runtime run these models.
- GPTs: Generative Pre-Trained Transformers
- LLM: Large Language Models
- NLP: Natural Language Processing
- MLP: Multilayer Perceptron
- ASR: Automatic Speech Recognition
- WER: Word Error Rate
- CER: Character Error Rate

---

### Overview (`packages/types-generator/README.md`)

# PeerTube typings

These **Typescript** *types* are mainly used to write **PeerTube** plugins.

## Installation

Npm:
```
npm install --save-dev @peertube/peertube-types
```

## Usage

> See [contribute-plugins](https://docs.joinpeertube.org/contribute/plugins#typescript) **Typescript** section of the doc.

---

### Overview (`client/src/standalone/embed-player-api/README.md`)

# @peertube/embed-api

See https://docs.joinpeertube.org/api/embed-player

---

### Support Doc Api Quickstart (`support/doc/api/quickstart.md`)

# REST API quick start

## Detect a PeerTube instance

There are several ways to know if a website uses the PeerTube software:

 * The server exposes NodeInfo information: https://peertube2.cpy.re/nodeinfo/2.0.json
 * The server sends a `x-powered-by: PeerTube` header response to API requests
 * HTML pages include a `<meta property="og:platform" content="PeerTube">` tag

## Authentication

### Get client

Some endpoints need authentication. We use OAuth 2.0 so first fetch the client tokens:

::: code-group

```bash [Curl]
curl https://peertube.example.com/api/v1/oauth-clients/local
```

```js [JS]
const { client_id, client_secret } = await fetch('https://peertube.example.com/api/v1/oauth-clients/local', {
  headers: { 'Content-Type': 'application/json' }
}).then(res => res.json())
```

:::

Response example:

```json
{
  "client_id": "v1ikx5hnfop4mdpnci8nsqh93c45rldf",
  "client_secret": "AjWiOapPltI6EnsWQwlFarRtLh4u8tDt"
}
```

### Get user token

Now you can fetch the user token:

::: code-group

```bash [Curl]
curl -X POST \
 -d "client_id=v1ikx5hnfop4mdpnci8nsqh93c45rldf&client_secret=AjWiOapPltI6EnsWQwlFarRtLh4u8tDt&grant_type=password&response_type=code&username=your_user&password=your_password" \
  https://peertube.example.com/api/v1/users/token
```

```js [JS]
const { access_token } = await fetch('https://peertube.example.com/api/v1/users/token', {
  contentType: 'application/x-www-form-urlencoded',
  method: 'POST',
  body: new URLSearchParams({
    client_id: '...',
    client_secret: '...',
    username: '...',
    password: '...',
    grant_type: 'password'
  })
}).then(res => res.json())
```
:::

Response example:

```json
{
  "access_token": "90286a0bdf0f7315d9d3fe8dabf9e1d2be9c97d0",
  "token_type": "Bearer",
  "expires_in": 14399,
  "refresh_token": "2e0d675df9fc96d2e4ec8a3ebbbf45eca9137bb7"
}
```

Just use the `access_token` in the `Authorization` header:

```bash
curl -H 'Authorization: Bearer 90286a0bdf0f7315d9d3fe8dabf9e1d2be9c97d0' https://peertube.example.com/api/v1/jobs/completed
```


## List videos

```bash
curl https://peertube.example.com/api/v1/videos
```

## Libraries

Convenience libraries can be generated automatically from the [OpenAPI specification](https://github.com/Chocobozzz/PeerTube/blob/develop/support/doc/api/openapi.yaml) for [languages supported by the OpenAPI generator](https://openapi-generator.tech/docs/generators/#client-generators).

---

### Support Doc Dependencies (`support/doc/dependencies.md`)

# Dependencies

:warning: **Warning**: dependencies guide is maintained by the community. Some parts may be outdated! :warning:

Main dependencies supported by PeerTube:

 * `node` LTS (**>= 22.22 and <25**)
 * `pnpm` >= 12.x
 * `postgres` >=14.x
 * `redis-server` >=6.2
 * `ffmpeg` >=4.3 (using a ffmpeg static build [is not recommended](https://github.com/Chocobozzz/PeerTube/issues/6308))
 * `python` >=3.8
 * `pip`


_note_: only **LTS** versions of external dependencies are supported. If no LTS version matching the version constraint is available, only **release** versions are supported.

_note_: some distributions still ship a PostgreSQL older than 14 in their default repositories. Check with `psql --version` after
installing, and if it is too old, install a supported release from the
[PostgreSQL official repositories](https://www.postgresql.org/download/) instead of the distribution package.

[[toc]]

## Debian / Ubuntu and derivatives

1. On a fresh Debian/Ubuntu, as root user, install basic utility programs needed for the installation

    ```sh
    sudo apt-get install curl sudo unzip vim
    ```

1. It would be wise to disable root access and to continue this tutorial with a user with sudoers group access. You can see a guide for how to do this in Debian/Ubuntu [here](https://www.digitalocean.com/community/tutorials/how-to-add-and-delete-users-on-ubuntu-20-04).

1. Install NodeJS 22.x: https://nodesource.com/products/distributions

1. Install [PNPM](https://pnpm.io/fr/installation):

    ```sh
    sudo npm install pnpm
    ```

1. Install Python:

    ```sh
    sudo apt update
    sudo apt install python3-dev python3-pip python-is-python3
    python --version # Should be >= 3.8
    ```

1. Install common dependencies:

    ```sh
    sudo apt update
    sudo apt install certbot nginx ffmpeg postgresql postgresql-contrib openssl g++ make redis-server git cron wget
    ffmpeg -version # Should be >= 4.1
    g++ -v # Should be >= 5.x
    redis-server --version # Should be >= 6.x
    psql --version # Should be >= 14
    ```

    Debian 11 (bullseye) and Ubuntu 20.04 ship PostgreSQL 13 or older: on these releases install PostgreSQL from the
    [PostgreSQL APT repository](https://www.postgresql.org/download/linux/ubuntu/) instead.

Now that dependencies are installed, before running PeerTube you should start PostgreSQL and Redis:

```sh
sudo systemctl start redis postgresql
```

## Arch Linux

Run:

```sh
sudo pacman -S nodejs-lts-iron ffmpeg postgresql openssl redis git wget unzip python python-pip base-devel npm nginx pnpm
```

Now that dependencies are installed, before running PeerTube you should start PostgreSQL and Redis:

```sh
sudo systemctl start redis postgresql
```

## CentOS 7

1. Install NodeJS 22.x: https://nodesource.com/products/distributions

1. Install [PNPM](https://pnpm.io/fr/installation):

    ```sh
    sudo npm install pnpm
    ````

1. Install or compile ffmpeg:

    * Install - [https://linoxide.com/linux-how-to/install-ffmpeg-centos-7/](https://linoxide.com/linux-how-to/install-ffmpeg-centos-7/)
    * Compile - [https://gist.github.com/mustafaturan/7053900#file-latest-ffmpeg-centos6-sh](https://gist.github.com/mustafaturan/7053900#file-latest-ffmpeg-centos6-sh)

1. Install Packages:

    ```sh
    sudo yum update
    sudo yum install epel-release centos-release-scl
    sudo yum update
    sudo yum install nginx postgresql postgresql-server postgresql-contrib openssl gcc-c++ make wget redis git devtoolset-7
    ```

    :warning: The CentOS 7 base repository provides PostgreSQL 9.2, which is too old for PeerTube. Install PostgreSQL >= 14 from
    the [PostgreSQL Yum repository](https://www.postgresql.org/download/linux/redhat/) instead of the `postgresql*` packages above.

1. You need to use a more up to date version of G++ in order to run the `npm run install-node-dependencies` command, hence the installation of devtoolset-7.

    ```sh
    sudo scl enable devtoolset-7 bash
    ```

    Later when you invoke any node command, please prefix them with `CC=/opt/rh/devtoolset-7/root/usr/bin/gcc CXX=/opt/rh/devtoolset-7/root/usr/bin/g++`, such as with:

    ```sh
    sudo -H -u peertube CC=/opt/rh/devtoolset-7/root/usr/bin/gcc CXX=/opt/rh/devtoolset-7/root/usr/bin/g++ npm run install-node-dependencies -- --production
    ```

1. Initialize the PostgreSQL database:

    ```sh
    sudo PGSETUP_INITDB_OPTIONS='--auth-host=md5' postgresql-setup --initdb --unit postgresql
    ```

Now that dependencies are installed, before running PeerTube you should enable and start PostgreSQL and Redis:

```sh
sudo systemctl enable --now redis
sudo systemctl enable --now postgresql
```

## Centos 8

1. Install NodeJS 22.x: https://nodesource.com/products/distributions

1. Install [PNPM](https://pnpm.io/fr/installation):

    ```sh
    sudo npm install pnpm
    ````

1. Install or compile ffmpeg:

    ```sh
    sudo dnf install epel-release dnf-utils
    sudo yum-config-manager --set-enabled powertools
    sudo yum-config-manager --add-repo=https://negativo17.org/repos/epel-multimedia.repo
    sudo dnf install ffmpeg
    ```

1. Install packages:

    ```sh
    sudo dnf update
    sudo dnf install epel-release
    sudo dnf update
    sudo dnf module enable postgresql:16 # Default stream is PostgreSQL 10, too old for PeerTube
    sudo dnf install nginx postgresql postgresql-server postgresql-contrib openssl gcc-c++ make wget redis git unzip
    psql --version # Should be >= 14
    ```

    Use `sudo dnf module list postgresql` to see the streams available on your release, and pick the most recent one >= 14.

1. You'll need a symlink for python3 to python for youtube-dl to work

    ```sh
    sudo ln -s /usr/bin/python3 /usr/bin/python
    ```

1. Initialize the PostgreSQL database:

    ```sh
    sudo PGSETUP_INITDB_OPTIONS='--auth-host=md5' postgresql-setup --initdb --unit postgresql
    ```

Now that dependencies are installed, before running PeerTube you should enable and start PostgreSQL and Redis:

```sh
sudo systemctl enable --now redis
sudo systemctl enable --now postgresql
```

## Rocky Linux 8.4

1. Pull the latest updates:
    ```sh
    sudo dnf update -y
    ```

1. Install NodeJS 22.x:
    ```sh
    sudo dnf module install -y nodejs:22
    ```

1. Install PNPM:
    ```sh
    sudo npm install pnpm
    ```

1. Install or compile ffmpeg (if you want to compile... enjoy):
    ```sh
    sudo dnf install -y epel-release
    sudo dnf --enablerepo=powertools install -y SDL2 SDL2-devel
    sudo dnf install -y --nogpgcheck https://download1.rpmfusion.org/free/el/rpmfusion-free-release-8.noarch.rpm https://download1.rpmfusion.org/nonfree/el/rpmfusion-nonfree-release-8.noarch.rpm
    sudo dnf install -y ffmpeg
    sudo dnf update -y
    ```

1. Install PostgreSQL and Python3 and other stuff:
    ```sh
    sudo dnf module enable -y postgresql:16 # Default stream is PostgreSQL 10, too old for PeerTube
    sudo dnf install -y nginx postgresql postgresql-server postgresql-contrib openssl gcc-c++ make wget redis git python3 python3-pip
    psql --version # Should be >= 14
    sudo ln -s /usr/bin/python3 /usr/bin/python
    sudo PGSETUP_INITDB_OPTIONS='--auth-host=md5' postgresql-setup --initdb --unit postgresql
    sudo systemctl enable --now redis
    sudo systemctl enable --now postgresql
    ```

1. Unknown missing steps:
    - Steps missing here... these were adapted from the CentOS 8 steps which abruptly ended.
    - /var/www/peertube does not exist yet (expected? done in future steps? documentation?).
    - Nothing about Certbot, NGINX, Firewall settings, and etc.
    - Hopefully someone can suggest what is missing here with some hints so I can add it?

## Fedora

1. Upgrade your packages:

    ```sh
    dnf upgrade
    ```

1. (Optional) Install certbot (choose instructions for your distribution):
[https://certbot.eff.org/all-instructions](https://certbot.eff.org/all-instructions)

1. Install NodeJS 22.x: https://nodesource.com/products/distributions

1. Install PNPM:
    ```sh
    sudo npm install pnpm
    ```

1. Enable [RPM Fusion](https://rpmfusion.org) for Fedora (available for x86, x86_64, armhfp)

    ```sh
    sudo dnf install https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm
    ```

    This is necessary because `ffmpeg` is not in the Fedora repos.

1. Run:

    ```sh
    sudo dnf install nginx ffmpeg postgresql-server postgresql-contrib openssl gcc-c++ make redis git vim
    ffmpeg -version # Should be >= 4.1
    g++ -v # Should be >= 5.x
    redis-server --version # Should be >= 6.x
    ```

1. Configure nginx

    ```sh
    sudo mkdir /etc/nginx/sites-available
    sudo mkdir /etc/nginx/sites-enabled
    sudo ln -s /etc/nginx/sites-enabled/peertube /etc/nginx/conf.d/peertube.conf
    ```

1. Post-installation

    _from [PostgreSQL documentation](https://www.postgresql.org/download/linux/redhat/):_
    > Due to policies for Red Hat family distributions, the PostgreSQL installation will not be enabled for automatic start or have the database initialized automatically.

    ```sh
    # PostgreSQL
    sudo PGSETUP_INITDB_OPTIONS='--auth-host=md5' postgresql-setup --initdb --unit postgresql
    sudo systemctl enable postgresql.service
    sudo systemctl start postgresql.service
    # Nginx
    sudo systemctl enable nginx.service
    sudo systemctl start nginx.service
    # Redis
    sudo systemctl enable redis.service
    sudo systemctl start redis.service
    ```

1. Firewall

    By default, you cannot access your server via public IP. To do so, you must configure the firewall.

      Ports used by peertube dev setup:
    ```sh
    sudo firewall-cmd --permanent --zone=public --add-port=3000/tcp
    sudo firewall-cmd --permanent --zone=public --add-port=9000/tcp
    ```

    * Optional

    ```sh
    sudo firewall-cmd --permanent --zone=public --add-service=http
    sudo firewall-cmd --permanent --zone=public --add-service=https
    ```

    * Reload firewall

    ```sh
    sudo firewall-cmd --reload
    ```

1. Configure max ports

    This is necessary if you are running dev setup, otherwise you will have errors with `nodemon`

    ```sh
    echo fs.inotify.max_user_watches=582222 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
    ```

    [More info](https://stackoverflow.com/questions/34662574/node-js-getting-error-nodemon-internal-watch-failed-watch-enospc#34664097)

## Red Hat Enterprise Linux 8

1. Register system as root user to Red Hat Subscription Management (create a free Red Hat account if you don't have one yet).

    ```sh
    subscription-manager register --username <username> --password <password> --auto-attach
    dnf upgrade
    reboot
    ```

1. Install NodeJS

    ```sh
    sudo dnf module install nodejs:22
    ```

1. Install PNPM:
    ```sh
    sudo npm install pnpm
    ```

1. Install FFmpeg

    ```sh
    sudo subscription-manager repos --enable "codeready-builder-for-rhel-8-$(arch)-rpms"
    sudo dnf install --nogpgcheck https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm
    sudo dnf install --nogpgcheck https://mirrors.rpmfusion.org/free/el/rpmfusion-free-release-8.noarch.rpm
    sudo dnf upgrade
    sudo dnf install ffmpeg
    ```

1. Run:

    ```sh
    sudo dnf module enable postgresql:16 # Default stream is PostgreSQL 10, too old for PeerTube
    sudo dnf install nginx postgresql postgresql-server postgresql-contrib openssl gcc-c++ make wget redis git
    psql --version # Should be >= 14
    ```

1. You'll need a symlink for python3 to python for youtube-dl to work

    ```sh
    sudo alternatives --set python3 /usr/bin/python
    ```

1. Initialize the PostgreSQL database:

    ```sh
    sudo PGSETUP_INITDB_OPTIONS='--auth-host=md5' postgresql-setup --initdb --unit postgresql
    ```

    Now that dependencies are installed, before running PeerTube you should enable and start PostgreSQL and Redis:

    ```sh
    sudo systemctl enable --now redis
    sudo systemctl enable --now postgresql
    ```

    If you are running the production guide, you also need to slightly pre-configure nginx, because nginx is packaged differently in the Red Hat family distributions:

1. Configure nginx

    ```sh
    sudo mkdir /etc/nginx/sites-available
    sudo mkdir /etc/nginx/sites-enabled
    sudo ln -s /etc/nginx/sites-enabled/peertube /etc/nginx/conf.d/peertube.conf
    sudo systemctl enable --now nginx
    ```

1. Firewall

    By default, you cannot access your server via public IP. To do so, you must configure firewall:

    * Ports used by peertube dev setup:
    ```sh
    sudo firewall-cmd --permanent --zone=public --add-port=3000/tcp
    sudo firewall-cmd --permanent --zone=public --add-port=9000/tcp
    ```
    * Optional

    ```sh
    sudo firewall-cmd --permanent --zone=public --add-service=http
    sudo firewall-cmd --permanent --zone=public --add-service=https
    ```

    * Reload firewall

    ```sh
    sudo firewall-cmd --reload
    ```

1. Configure max ports

    This is necessary if you are running dev setup, otherwise you will have errors with `nodemon`

    ```sh
    echo fs.inotify.max_user_watches=582222 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
    ```

    [More info](https://stackoverflow.com/questions/34662574/node-js-getting-error-nodemon-internal-watch-failed-watch-enospc#34664097)


## FreeBSD

On a fresh install of [FreeBSD](https://www.freebsd.org), new system or new jail:

1. bootstrap pkg, initialize db and install peertube's dependencies, always as root (sudo not yet installed):

    ```sh
    pkg
    pkg update
    pkg install -y sudo bash wget git python nginx pkgconf postgresql16-server postgresql16-contrib redis openssl node npm ffmpeg unzip
    ```

1. install `sharp` build dependencies: https://sharp.pixelplumbing.com/install/#building-from-source

1. Install PNPM:
    ```sh
    sudo npm install pnpm
    ```

1. Allow users in the wheel group (hope you don't forgot to add your user on wheel group!) to use sudo.

    ```sh
    visudo
    ```

    Uncomment the line 90

    ```
    %wheel ALL=(ALL) ALL
    ```

1. Enable nginx, redis, postgresql services and initialize database.

    ```sh
    sysrc postgresql_enable="YES"
    sysrc redis_enable="YES"
    sysrc nginx_enable="YES"
    ```

    Initialize database and start services

    ```sh
    service postgresql initdb
    service postgresql start
    service redis start
    service nginx start
    ```

## macOS

1. Add the packages:

    ```sh
    brew install ffmpeg nginx postgresql@16 openssl gcc make redis git
    brew install pnpm
    ```

1. Run the services:

    ```sh
    brew services run postgresql@16
    brew services run redis
    ```

    On macOS, the `postgresql` user can be `_postgres` instead of `postgres`.
    If `sudo -u postgres createuser -P peertube` gives you an `unknown user: postgres` error, you can try `sudo -u _postgres createuser -U peertube`.

## Gentoo

1. Add this to ``/etc/portage/sets/peertube``:

    ```
    net-libs/nodejs
    sys-apps/pnpm
    media-video/ffmpeg[x264] # Optionally add vorbis,vpx
    dev-db/postgresql:16 # Any slot >= 14 works
    dev-db/redis
    dev-vcs/git
    app-arch/unzip
    dev-lang/python
    dev-lang/python-exec
    www-servers/nginx

    # Optional, client for Let’s Encrypt:
    # app-crypt/certbot
    ```

1. If you are on a "stable" Gentoo you need to accept the testing keyword ~amd64 pnpm:

    ```sh
    mkdir -p /etc/portage/package.keywords
    cat << EOF >> /etc/portage/package.keywords/peertube
    # required by pnpm (argument) for PeerTube
    sys-apps/pnpm ~amd64
    EOF
    ```

1. Compile the peertube set:

    ```sh
    emerge -a @peertube
    ```

1. Initialize the PostgreSQL database if you just merged it:

    ```sh
    emerge --config postgresql
    ```

1. (For OpenRC) Enable and then start the services (replace with the correct PostgreSQL slot):

    ```sh
    rc-update add redis
    rc-update add postgresql-16
    rc-service redis start
    rc-service postgresql-16 start
    ```

1. Create Python version symlink for youtube-dl:

    ```sh
    emerge -1 python-exec
    ```

## OpenBSD

1. Install Packages:

    ```sh
    pkg_add sudo bash wget git python nginx pkgconf postgresql-server postgresql-contrib redis openssl
    ```

1. Install PNPM:
    ```sh
    sudo npm install pnpm
    ```

1. Allow users in the wheel group to use sudo

    ```sh
    visudo
    ```
    Uncomment line #43:

    ```
    %wheel ALL=(ALL) ALL
    ```

1. Enable services:

    ```sh
    rcctl enable postgresql redis nginx
    ```

## Other distributions

Feel free to update this file in a pull request!

---

### Support Doc Docker (`support/doc/docker.md`)

# Docker guide

This guide requires [docker](https://www.docker.com/community-edition) and
[docker-compose V2](https://docs.docker.com/compose/install/).

```shell
docker compose version # Must be > 2.x.x
```

## Install

**PeerTube does not support webserver host change**. Keep in mind your domain
name is definitive after your first PeerTube start.

#### Go to your workdir

:::info
The guide that follows assumes an empty workdir, but you can also clone the repository, use the master branch and `cd support/docker/production`.
:::

```shell
cd /your/peertube/directory
```

#### Get the latest Compose file

```shell
curl https://raw.githubusercontent.com/chocobozzz/PeerTube/master/support/docker/production/docker-compose.yml > docker-compose.yml
```

View the source of the file you're about to download: [docker-compose.yml](https://github.com/Chocobozzz/PeerTube/blob/master/support/docker/production/docker-compose.yml)

#### Get the latest env_file

```shell
curl https://raw.githubusercontent.com/Chocobozzz/PeerTube/master/support/docker/production/.env > .env
```

View the source of the file you're about to download: [.env](https://github.com/Chocobozzz/PeerTube/blob/master/support/docker/production/.env)

#### Tweak the `docker-compose.yml` file there according to your needs

```shell
sudo nano docker-compose.yml
```

#### Then tweak the `.env` file to change the environment variables settings

```shell
sudo nano .env
```

In the downloaded example [.env](https://github.com/Chocobozzz/PeerTube/blob/master/support/docker/production/.env), you must replace:
- `<MY POSTGRES USERNAME>`
- `<MY POSTGRES PASSWORD>`
- `<MY DOMAIN>` without 'https://'
- `<MY EMAIL ADDRESS>`
- `<MY PEERTUBE SECRET>`

Other environment variables are used in
[/support/docker/production/config/custom-environment-variables.yaml](https://github.com/Chocobozzz/PeerTube/blob/master/support/docker/production/config/custom-environment-variables.yaml) and can be
intuited from usage.

#### Webserver

::: info
The docker compose file includes a configured web server. You can skip this part and comment the appropriate section in the docker compose if you use another webserver/proxy.
:::

Install the template that the nginx container will use.
The container will generate the configuration by replacing `${WEBSERVER_HOST}` and `${PEERTUBE_HOST}` using your docker compose env file.

```shell
mkdir -p docker-volume/nginx docker-volume/nginx-logs
curl https://raw.githubusercontent.com/Chocobozzz/PeerTube/master/support/nginx/peertube > docker-volume/nginx/peertube
```

You need to manually generate the first SSL/TLS certificate using Let's Encrypt:

```shell
mkdir -p docker-volume/certbot
docker run -it --rm --name certbot -p 80:80 -v "$(pwd)/docker-volume/certbot/conf:/etc/letsencrypt" certbot/certbot certonly --standalone
```

A dedicated container in the docker-compose will automatically renew this certificate and reload nginx.


#### Test your setup

_note_: Newer versions of compose are called with `docker compose` instead of `docker-compose`, so remove the dash in all steps that use this command if you are getting errors.

Run your containers:

```shell
docker compose up
```

#### Obtaining your automatically-generated admin credentials

You can change the automatically created password for user root by running this command from peertube's root directory:
```shell
docker compose exec -u peertube peertube npm run reset-password -- -u root
```

You can also grep your peertube container's logs for the default `root` password. You're going to want to run `docker-compose logs peertube | grep -A1 root` to search the log output for your new PeerTube's instance admin credentials which will look something like this.

```bash
docker compose logs peertube | grep -A1 root

peertube_1  | [example.com:443] 2019-11-16 04:26:06.082 info: Username: root
peertube_1  | [example.com:443] 2019-11-16 04:26:06.083 info: User password: abcdefghijklmnop
```

#### Obtaining Your Automatically Generated DKIM DNS TXT Record

[DKIM](https://en.wikipedia.org/wiki/DomainKeys_Identified_Mail) signature sending and RSA keys generation are enabled by the default Postfix image `mwader/postfix-relay` with [OpenDKIM](http://www.opendkim.org/).

Run `cat ./docker-volume/opendkim/keys/*/*.txt` to display your DKIM DNS TXT Record containing the public key to configure to your domain :

```bash
cat ./docker-volume/opendkim/keys/*/*.txt

peertube._domainkey.mydomain.tld.	IN	TXT	( "v=DKIM1; h=sha256; k=rsa; "
	  "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0Dx7wLGPFVaxVQ4TGym/eF89aQ8oMxS9v5BCc26Hij91t2Ci8Fl12DHNVqZoIPGm+9tTIoDVDFEFrlPhMOZl8i4jU9pcFjjaIISaV2+qTa8uV1j3MyByogG8pu4o5Ill7zaySYFsYB++cHJ9pjbFSC42dddCYMfuVgrBsLNrvEi3dLDMjJF5l92Uu8YeswFe26PuHX3Avr261n"
	  "j5joTnYwat4387VEUyGUnZ0aZxCERi+ndXv2/wMJ0tizq+a9+EgqIb+7lkUc2XciQPNuTujM25GhrQBEKznvHyPA6fHsFheymOuB763QpkmnQQLCxyLygAY9mE/5RY+5Q6J9oDOQIDAQAB" )  ; ----- DKIM key peertube for mydomain.tld
```

#### Administrator password

See the production guide ["Administrator" section](https://docs.joinpeertube.org/install/any-os#administrator)

#### What now?

See the production guide ["What now" section](https://docs.joinpeertube.org/install/any-os#what-now).

## Upgrade

::: warning
Check the changelog (in particular the *IMPORTANT NOTES* section): https://github.com/Chocobozzz/PeerTube/blob/develop/CHANGELOG.md
:::

Pull the latest images:

```shell
cd /your/peertube/directory
docker compose pull
```

Stop, delete the containers and internal volumes (to invalidate static client files shared by `peertube` and `webserver` containers):

```shell
docker compose down -v
```

Update the nginx configuration:

```shell
mv docker-volume/nginx/peertube docker-volume/nginx/peertube.bak
curl https://raw.githubusercontent.com/Chocobozzz/PeerTube/master/support/nginx/peertube > docker-volume/nginx/peertube
```

Rerun PeerTube:

```shell
docker compose up -d
```

## Upgrade PostgreSQL container

If you want to upgrade your PostgreSQL container version (for example because your current version is about to no longer be supported),
you need to plan downtime (to export current cluster and re-import data in new one).

When you're ready, go inside your PeerTube docker compose directory:

```sh
cd /docker-compose/directory
```

Prepare the backups directory and stop all containers except the database:

```sh
mkdir -p backups
docker compose stop peertube webserver certbot
```

Go inside the database container:

```sh
docker compose exec -it postgres /bin/bash
```

And export the database (you don't need to replace `$POSTGRES_*` variables, they are automatically set by your env file from docker compose):

```sh
export PGUSER="$POSTGRES_USER"
export PGDATABASE="$POSTGRES_DB"
export PGPASSWORD="$POSTGRES_PASSWORD"
pg_dumpall > "/tmp/pg.dump"
```

Exit the container:

```sh
exit
```

Copy the dump from the container:

```sh
docker compose cp postgres:/tmp/pg.dump backups/pg.dump
```


Stop the database container and prepare the data for the new cluster:

```sh
docker compose stop postgres
mv ./docker-volume/db ./docker-volume/db.bak
mkdir ./docker-volume/db && chmod 700 ./docker-volume/db
```

Upgrade your PostgreSQL container version (for example replace `postgres:13-alpine` by `postgres:17-alpine`):

```sh
vim docker-compose.yml
```

Pull new PostgreSQL Docker image:

```sh
docker compose pull
```

Restart PostgreSQL only container and wait until you see: `database system is ready to accept connections`

```sh
docker compose up -d postgres
docker compose logs -f postgres
```

Copy the database dump inside the container:

```sh
docker compose cp "backups/pg.dump" postgres:/tmp/pg.dump
```

Go inside the container

```sh
docker compose exec -it postgres /bin/bash
```

Check the PostgreSQL version and re-import database data.
Then, reset the PeerTube database user password to fix a potential authentication issue if the old password hash algorithm has been deprecated.

```sh
export PGUSER="$POSTGRES_USER"
export PGDATABASE="$POSTGRES_DB"
export PGPASSWORD="$POSTGRES_PASSWORD"
psql -U "$POSTGRES_USER" -c "SELECT version();"
psql -U "$POSTGRES_USER" -f /tmp/pg.dump
psql -U "$POSTGRES_USER" -c "ALTER USER $POSTGRES_USER WITH PASSWORD '$POSTGRES_PASSWORD';"
```

Exit the container:

```sh
exit
```

Restart other services and check everything is fine:

```sh
docker compose up -d peertube webserver certbot
docker compose logs -f peertube
```


If you're happy with the results, you can remove backups directory and old data directories:

```sh
rm -rf ./docker-volume/db.bak backups
```

## Build

### Production

```shell
git clone https://github.com/chocobozzz/PeerTube /tmp/peertube
cd /tmp/peertube
docker build . -f ./support/docker/production/Dockerfile
```

### Development

We don't have a Docker image for development. See [the CONTRIBUTING guide](https://docs.joinpeertube.org/contribute/getting-started#develop) for more information on how you can hack PeerTube!

---

### Support Doc Production (`support/doc/production.md`)

# Production guide

  * [Installation](#installation)
  * [Upgrade](#upgrade)

## Installation

Please don't install PeerTube for production on a device behind a low bandwidth connection (example: your ADSL link).
If you want information about the appropriate hardware to run PeerTube, please see the [FAQ](https://joinpeertube.org/en_US/faq#should-i-have-a-big-server-to-run-peertube).

### :hammer: Dependencies

Follow the steps of the [dependencies guide](/support/doc/dependencies.md).

### :construction_worker: PeerTube user

Create a `peertube` user with `/var/www/peertube` home:

::: code-group

```bash [GNU/Linux]
sudo useradd -m -d /var/www/peertube -s /usr/sbin/nologin peertube
```

```bash [FreeBSD]
sudo pw useradd -n peertube -d /var/www/peertube -s /usr/sbin/nologin -m
```

:::

Ensure the peertube root directory is traversable by nginx:

```bash
sudo chmod 755 /var/www/peertube
```

### :card_file_box: Database

Create the production database and a peertube user inside PostgreSQL:

```bash
cd /var/www/peertube
sudo -u postgres createuser -P peertube
```

Here you should enter a password for PostgreSQL `peertube` user, that should be copied in `production.yaml` file.
Don't just hit enter else it will be empty.

```bash
sudo -u postgres createdb -O peertube -E UTF8 -T template0 peertube_prod
```

Then enable extensions PeerTube needs:

```bash
sudo -u postgres psql -c "CREATE EXTENSION pg_trgm;" peertube_prod
sudo -u postgres psql -c "CREATE EXTENSION unaccent;" peertube_prod
```

### :page_facing_up: Prepare PeerTube directory

Fetch the latest tagged version of Peertube:

```bash
VERSION=$(curl -s https://api.github.com/repos/chocobozzz/peertube/releases/latest | grep tag_name | cut -d '"' -f 4) && echo "Latest Peertube version is $VERSION"
```


Open the peertube directory, create a few required directories:

```bash
cd /var/www/peertube
sudo -u peertube mkdir config storage versions
sudo -u peertube chmod 750 config/
```


Download the latest version of the Peertube client, unzip it and remove the zip:

```bash
cd /var/www/peertube/versions
# Releases are also available on https://builds.joinpeertube.org/release
sudo -u peertube wget -q "https://github.com/Chocobozzz/PeerTube/releases/download/${VERSION}/peertube-${VERSION}.zip"
sudo -u peertube unzip -q peertube-${VERSION}.zip && sudo -u peertube rm peertube-${VERSION}.zip
```


Install Peertube:

::: code-group

```bash [GNU/Linux]
cd /var/www/peertube
sudo -u peertube ln -s versions/peertube-${VERSION} ./peertube-latest
cd ./peertube-latest && sudo -H -u peertube npm run install-node-dependencies -- --production
```

```bash [FreeBSD]
cd /var/www/peertube
sudo -u peertube ln -s versions/peertube-${VERSION} ./peertube-latest
cd ./peertube-latest && sudo -H -u peertube npm run install-node-dependencies -- --production
sudo -u peertube pnpm add --workspace-root --no-lockfile --prod node-addon-api node-gyp
sudo -u peertube SHARP_FORCE_GLOBAL_LIBVIPS=1 npm explore sharp -- npm run build
```

:::

### :wrench: PeerTube configuration

Copy the default configuration file that contains the default configuration provided by PeerTube.
You **must not** update this file.

```bash
cd /var/www/peertube
sudo -u peertube cp peertube-latest/config/default.yaml config/default.yaml
```

Now copy the production example configuration:

```bash
cd /var/www/peertube
sudo -u peertube cp peertube-latest/config/production.yaml.example config/production.yaml
```

Then edit the `config/production.yaml` file according to your webserver and database configuration. In particular:
 * `webserver`: Reverse proxy public information
 * `secrets`: Secret strings you must generate manually (PeerTube version >= 5.0)
 * `database`: PostgreSQL settings
 * `redis`: Redis settings
 * `smtp`: If you want to use emails
 * `admin.email`: To correctly fill `root` user email

Keys defined in `config/production.yaml` will override keys defined in `config/default.yaml`.

**PeerTube does not support webserver host change**. Even though [PeerTube CLI can help you to switch hostname](https://docs.joinpeertube.org/maintain/tools#update-host-js) there's no official support for that since it is a risky operation that might result in unforeseen errors.

### :truck: Webserver

We only provide official configuration files for Nginx.

Copy the nginx configuration template:

```bash
sudo cp /var/www/peertube/peertube-latest/support/nginx/peertube /etc/nginx/sites-available/peertube
```

Set the domain for the webserver configuration file by replacing `[peertube-domain]` with the domain for the peertube server:

```bash
sudo sed -i 's/${WEBSERVER_HOST}/[peertube-domain]/g' /etc/nginx/sites-available/peertube
sudo sed -i 's/${PEERTUBE_HOST}/127.0.0.1:9000/g' /etc/nginx/sites-available/peertube
```

Then modify the webserver configuration file. Please pay attention to:
 * the `alias` and `root` directives paths, the paths must correspond to your PeerTube filesystem location
 * the `proxy_limit_rate` and `limit_rate` directives if you plan to stream high bitrate videos (like 4K at 60FPS)

```bash
sudo vim /etc/nginx/sites-available/peertube
```

Activate the configuration file:

```bash
sudo ln -s /etc/nginx/sites-available/peertube /etc/nginx/sites-enabled/peertube
```

To generate the certificate for your domain as required to make https work you can use [Let's Encrypt](https://letsencrypt.org/):

```bash
sudo systemctl stop nginx
sudo certbot certonly --standalone --post-hook "systemctl restart nginx"
sudo systemctl restart nginx
```

Certbot should have installed a cron to automatically renew your certificate.
Since our nginx template supports webroot renewal, we suggest you to update the renewal config file to use the `webroot` authenticator:

```bash
# Replace authenticator = standalone by authenticator = webroot
# Add webroot_path = /var/www/certbot
sudo vim /etc/letsencrypt/renewal/your-domain.com.conf
```

If you plan to have many concurrent viewers on your PeerTube instance, consider increasing `worker_connections` value: https://nginx.org/en/docs/ngx_core_module.html#worker_connections.

<details>
<summary><strong>If using FreeBSD</strong></summary>

On FreeBSD you can use [Dehydrated](https://dehydrated.io/) `security/dehydrated` for [Let's Encrypt](https://letsencrypt.org/)

```bash
sudo pkg install dehydrated
```
</details>

### :alembic: Linux TCP/IP Tuning

```bash
sudo cp /var/www/peertube/peertube-latest/support/sysctl.d/30-peertube-tcp.conf /etc/sysctl.d/
sudo sysctl -p /etc/sysctl.d/30-peertube-tcp.conf
```

Your distro may enable this by default, but at least Debian 9 does not, and the default FIFO
scheduler is quite prone to "Buffer Bloat" and extreme latency when dealing with slower client
links as we often encounter in a video server.

### :bricks: systemd

If your OS uses systemd, copy the configuration template:

```bash
sudo cp /var/www/peertube/peertube-latest/support/systemd/peertube.service /etc/systemd/system/
```

Check the service file (PeerTube paths and security directives):

```bash
sudo vim /etc/systemd/system/peertube.service
```


Tell systemd to reload its config:

```bash
sudo systemctl daemon-reload
```

If you want to start PeerTube on boot:

```bash
sudo systemctl enable peertube
```

Run:

```bash
sudo systemctl start peertube
sudo journalctl -feu peertube
```

<details>
<summary><strong>If using FreeBSD</strong></summary>

On FreeBSD, copy the startup script and update rc.conf:

```bash
sudo install -m 0555 /var/www/peertube/peertube-latest/support/freebsd/peertube /usr/local/etc/rc.d/
sudo sysrc peertube_enable="YES"
```

Run:

```bash
sudo service peertube start
```
</details>

<details>
<summary><strong>If using OpenRC</strong></summary>

If your OS uses OpenRC, copy the service script:

```bash
sudo cp /var/www/peertube/peertube-latest/support/init.d/peertube /etc/init.d/
sudo cp /var/www/peertube/peertube-latest/support/conf.d/peertube /etc/conf.d/
```

If you want to start PeerTube on boot:

```bash
sudo rc-update add peertube default
```

Run and print last logs:

```bash
sudo /etc/init.d/peertube start
tail -f /var/log/peertube/peertube.log
```
</details>

### :technologist: Administrator

The administrator username is `root` and the password is automatically generated. It can be found in PeerTube
logs (path defined in `production.yaml`). You can also set another password with:

```bash
cd /var/www/peertube/peertube-latest && sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run reset-password -- -u root
```

Alternatively you can set the environment variable `PT_INITIAL_ROOT_PASSWORD`,
to your own administrator password, although it must be 6 characters or more.

### :tada: What now?

Now your instance is up you can:

 * Add your instance to the public PeerTube instances index if you want to: https://instances.joinpeertube.org/
 * Check [available CLI tools](/support/doc/tools.md)

## Upgrade

### PeerTube instance

**Check the changelog (in particular the *IMPORTANT NOTES* section):** https://github.com/Chocobozzz/PeerTube/blob/develop/CHANGELOG.md

Run the upgrade script (the password it asks is PeerTube's database user password):

::: code-group

```bash [GNU/Linux]
cd /var/www/peertube/peertube-latest/scripts && sudo -H -u peertube ./upgrade.sh
```

```bash [FreeBSD]
cd /var/www/peertube/peertube-latest/scripts && sudo -H -u peertube ./upgrade.sh
sudo -u peertube pnpm add --workspace-root --no-lockfile --prod node-addon-api node-gyp
sudo -u peertube SHARP_FORCE_GLOBAL_LIBVIPS=1 npm explore sharp -- npm run build
```

:::

If you have `git` installed on your system, the upgrade will create a `production.yaml.new` file with differences marked as merge conflicts.
Review this file and replace your existing `production.yaml` with it before restarting.

```bash
# Make sure you first updated your configuration per the note above
sudo systemctl restart peertube # Or use your OS command to restart PeerTube if you don't use systemd
```

You may want to run `sudo -u peertube pnpm store prune` after several upgrades to free up disk space.

<details>
<summary><strong>Prefer manual upgrade?</strong></summary>

Make a SQL backup

```bash
SQL_BACKUP_PATH="backup/sql-peertube_prod-$(date -Im).bak" && \
    cd /var/www/peertube && sudo -u peertube mkdir -p backup && \
    sudo -u postgres pg_dump -F c peertube_prod | sudo -u peertube tee "$SQL_BACKUP_PATH" >/dev/null
```

Fetch the latest tagged version of Peertube:

```bash
VERSION=$(curl -s https://api.github.com/repos/chocobozzz/peertube/releases/latest | grep tag_name | cut -d '"' -f 4) && echo "Latest Peertube version is $VERSION"
```

Download the new version and unzip it:

```bash
cd /var/www/peertube/versions && \
    sudo -u peertube wget -q "https://github.com/Chocobozzz/PeerTube/releases/download/${VERSION}/peertube-${VERSION}.zip" && \
    sudo -u peertube unzip -o peertube-${VERSION}.zip && \
    sudo -u peertube rm peertube-${VERSION}.zip
```

Install node dependencies:

```bash
cd /var/www/peertube/versions/peertube-${VERSION} && \
    sudo -H -u peertube npm run install-node-dependencies -- --production
```

Copy new configuration defaults values and update your configuration file:

```bash
sudo -u peertube cp /var/www/peertube/versions/peertube-${VERSION}/config/default.yaml /var/www/peertube/config/default.yaml
diff -u /var/www/peertube/versions/peertube-${VERSION}/config/production.yaml.example /var/www/peertube/config/production.yaml
```

Change the link to point to the latest version:

```bash
cd /var/www/peertube && \
    sudo unlink ./peertube-latest && \
    sudo -u peertube ln -s versions/peertube-${VERSION} ./peertube-latest
```
</details>

### Update PeerTube configuration

If your system has `git` installed, the auto upgrade script should have created a `config/production.yaml.new` file that merges your current configuration file with the new configuration keys introduced by the new PeerTube version.

Review the file, check and fix any potential conflicts:

```bash
cd /var/www/peertube && sudo -u peertube diff config/production.yaml config/production.yaml.new
```

Then replace your current configuration file by the new one:

```bash
cd /var/www/peertube && sudo -u peertube cp config/production.yaml.new config/production.yaml
```

### Update nginx configuration

Check changes in nginx configuration:

```bash
cd /var/www/peertube/versions
diff -u "$(ls -t | head -2 | tail -1)/support/nginx/peertube" "$(ls -t | head -1)/support/nginx/peertube"
```

### Update systemd service

Check changes in systemd configuration:

```bash
cd /var/www/peertube/versions
diff -u "$(ls -t | head -2 | tail -1)/support/systemd/peertube.service" "$(ls -t | head -1)/support/systemd/peertube.service"
```

<details>
<summary><strong>If using OpenRC</strong></summary>

```bash
cd /var/www/peertube/versions
diff -u "$(ls -t | head -2 | tail -1)/support/init.d/peertube" "$(ls -t | head -1)/support/init.d/peertube"
diff -u "$(ls -t | head -2 | tail -1)/support/conf.d/peertube" "$(ls -t | head -1)/support/conf.d/peertube"
```
</details>

### Restart PeerTube

If you changed your nginx configuration:

```bash
sudo systemctl reload nginx
```

If you changed your systemd configuration:

```bash
sudo systemctl daemon-reload
```

Restart PeerTube and check the logs:

```bash
sudo systemctl restart peertube && sudo journalctl -fu peertube
```

### Things went wrong?

Change `peertube-latest` destination to the previous version and restore your SQL backup:

```bash
OLD_VERSION="v0.42.42" && SQL_BACKUP_PATH="backup/sql-peertube_prod-20180119-1018.bak" && \
  cd /var/www/peertube && sudo -u peertube unlink ./peertube-latest && \
  sudo -u peertube ln -s "versions/peertube-$OLD_VERSION" peertube-latest && \
  sudo -u postgres pg_restore -c -C -d peertube_prod "$SQL_BACKUP_PATH" && \
  sudo systemctl restart peertube
```

---

### Support Doc Tools (`support/doc/tools.md`)

# CLI tools guide

[[toc]]

## Remote PeerTube CLI

`peertube-cli` is a tool that communicates with a PeerTube instance using its [REST API](https://docs.joinpeertube.org/api-rest-reference.html).
It can be launched from a remote server/computer to easily upload videos, manage plugins, redundancies etc.

### Installation

Ensure you have `node` installed on your system:

```bash
node --version # Should be >= 22.x
```

Then install the CLI:

```bash
sudo npm install @peertube/peertube-cli
```

### CLI wrapper

The wrapper provides a convenient interface to the following sub-commands.

```
Usage: peertube-cli [command] [options]

Options:
  -v, --version                     output the version number
  -h, --help                        display help for command

Commands:
  auth                              Register your accounts on remote instances to use them with other commands
  upload|up [options]               Upload a video on a PeerTube instance
  redundancy|r                      Manage instance redundancies
  plugins|p                         Manage instance plugins/themes
  get-access-token|token [options]  Get a peertube access token
  help [command]                    display help for command
```

The wrapper can keep track of instances you have an account on. We limit to one account per instance for now.

```bash
peertube-cli auth add -u 'PEERTUBE_URL' -U 'PEERTUBE_USER' --password 'PEERTUBE_PASSWORD'
```

Now list the account(s) you've created

```bash
peertube-cli auth list
```

```
┌──────────────────────────────┬──────────────────────────────┐
│ instance                     │ login                        │
├──────────────────────────────┼──────────────────────────────┤
│ 'PEERTUBE_URL'               │ 'PEERTUBE_USER'              │
└──────────────────────────────┴──────────────────────────────┘
```

You can now use that account to execute sub-commands without feeding the `--url`, `--username` and `--password` parameters:

```bash
peertube-cli upload <videoFile>
```

```bash
peertube-cli plugins list
...

```

#### peertube-cli upload

You can use this script to upload videos directly from the CLI.

Videos will be publicly available after transcoding (you can see them before that in your account on the web interface).

```bash
cd ${CLONE}
peertube-cli upload --help
```

#### peertube-cli plugins

Install/update/uninstall or list local or NPM PeerTube plugins:

```bash
cd ${CLONE}
peertube-cli plugins --help
peertube-cli plugins list --help
peertube-cli plugins install --help
peertube-cli plugins update --help
peertube-cli plugins uninstall --help

peertube-cli plugins install --path /my/plugin/path
peertube-cli plugins install --npm-name peertube-theme-example
```

#### peertube-cli redundancy

Manage (list/add/remove) video redundancies:

To list your videos that are duplicated by remote instances:

```bash
peertube-cli redundancy list-remote-redundancies
```

To list remote videos that your instance duplicated:

```bash
peertube-cli redundancy list-my-redundancies
```

To duplicate a specific video in your redundancy system:

```bash
peertube-cli redundancy add --video 823
```

To remove a video redundancy:

```bash
peertube-cli redundancy remove --video 823
```


## PeerTube runner

PeerTube supports VOD/Live transcoding and VOD transcription (PeerTube >= 6.2) by a remote PeerTube runner.

The runner communicates with the PeerTube instance using HTTP and WebSocket and doesn't need to have a public IP.
So you can run a runner on a classic server, a non-public server or even on your own computer!

You can read the admin documentation on how to use PeerTube runners on https://docs.joinpeertube.org/admin/remote-runners

### Runner installation

Ensure you have `node`, `ffmpeg` and `ffprobe` installed on your system:

```bash
node --version # Should be >= 22.x
ffprobe -version # Should be >= 4.3
ffmpeg -version # Should be >= 4.3
```

If you want to use video transcription:

```bash
pip install whisper-ctranslate2 # or pipx install whisper-ctranslate2 depending on your distribution
```

Then install the CLI:

```bash
sudo npm install @peertube/peertube-runner
```

### Configuration

The runner uses env paths like `~/.config`, `~/.cache` and `~/.local/share` directories to store runner configuration or temporary files.

Multiple PeerTube runners can run on the same OS by using the `--id` CLI option (each runner uses its own config/tmp directories):

```bash
peertube-runner [commands] --id instance-1
peertube-runner [commands] --id instance-2
peertube-runner [commands] --id instance-3
```

You can change the runner configuration (jobs concurrency, ffmpeg threads/nice, whisper engines/models, etc.) by editing `~/.config/peertube-runner-nodejs/[id]/config.toml`.

The runner TOML config template consists of:

```toml
[jobs]
# How much concurrent jobs the runner can execute in parallel
concurrency = 2

[ffmpeg]
# How much threads a ffmpeg process can use
# 0 -> let ffmpeg automatically choose
threads = 0
nice = 20

[transcription]
# Choose between "openai-whisper" or "whisper-ctranslate2"
# Engine binary has to be installed manually (unlike the PeerTube instance that can install whisper automatically)
engine = "whisper-ctranslate2"
# Optional whisper binary path if not available in global path
enginePath = "/var/prunner/.local/pipx/venvs/whisper-ctranslate2/bin/whisper-ctranslate2"
# Whisper model: "tiny", "base", "small", "medium", "large-v2" or "large-v3"
model = "large-v2"

# Registered instances are saved in the config file
[[registeredInstances]]
url = "..." # URL of the instance
runnerToken = "..." # Shared runner token secret
runnerName = "..." # Runner name declared to the PeerTube instance

[[registeredInstances]]
url = "..."
runnerToken = "..."
runnerName = "..."
```

### Run the server

#### In a shell

You need to run the runner in server mode first so it can run transcoding jobs of registered PeerTube instances:

```bash
peertube-runner server
```

You can also decide which kind of job the runner can execute with `--enable-job <type>` option.
This way you can have one dedicated runner for transcription tasks (on a GPU machine for example) and another one for transcoding tasks.

Only transcription tasks

```bash
peertube-runner server --enable-job video-transcription
```

Only VOD transcoding tasks

```bash
peertube-runner server --enable-job vod-web-video-transcoding --enable-job vod-hls-transcoding --enable-job vod-audio-merge-transcoding
```

Only "studio" transcoding

```bash
peertube-runner server --enable-job video-studio-transcoding
```

Only "live" transcoding

```bash
peertube-runner server --enable-job live-rtmp-hls-transcoding
```

#### As a Systemd service

If your OS uses systemd, you can also configure a service so that the runner starts automatically.

To do so, first create a dedicated user. Here, we are calling it `prunner`, but you can choose whatever name you want.
We are using `/srv/prunner` as his home dir, but you can choose any other path.

```bash
useradd -m -d /srv/prunner -s /usr/sbin/nologin prunner
```

::: info Note
If you want to use `/home/prunner`, you have to set `ProtectHome=false` in the systemd configuration (see below).
:::

Now, you can create the `/etc/systemd/system/prunner.service` file (don't forget to adapt path and user/group names if you changed it):

```Systemd
[Unit]
Description=PeerTube runner daemon
After=network.target

[Service]
Type=simple
Environment=NODE_ENV=production
User=prunner
Group=prunner
ExecStart=peertube-runner server
WorkingDirectory=/srv/prunner
SyslogIdentifier=prunner
Restart=always

; Some security directives.
; Mount /usr, /boot, and /etc as read-only for processes invoked by this service.
ProtectSystem=full
; Sets up a new /dev mount for the process and only adds API pseudo devices
; like /dev/null, /dev/zero or /dev/random but not physical devices. Disabled
; by default because it may not work on devices like the Raspberry Pi.
PrivateDevices=false
; Ensures that the service process and all its children can never gain new
; privileges through execve().
NoNewPrivileges=true
; This makes /home, /root, and /run/user inaccessible and empty for processes invoked
; by this unit. Make sure that you do not depend on data inside these folders.
ProtectHome=true
; Drops the sys admin capability from the daemon.
CapabilityBoundingSet=~CAP_SYS_ADMIN

[Install]
WantedBy=multi-user.target
```

:::info Note
You can add the parameter `--id instance-1` on the `ExecStart` line, if you want to have multiple instances.
You can then create multiple separate services. They can use the same user and path.
:::

Finally, to enable the service for the first time:

```bash
systemctl daemon-reload
systemctl enable prunner.service
systemctl restart prunner.service
```

Next time, if you need to start/stop/restart the service:

```bash
systemctl stop prunner.service
systemctl start prunner.service
systemctl restart prunner.service
```

You can also check the status (and last logs):

```bash
systemctl status prunner.service
```

To edit the runner configuration: juste edit the `/srv/prunner/.config/peertube-runner-nodejs/default/config.toml` file,
and restart the service (this file will be created when the runner starts for the first time).

If you are using the `--id` parameter, you can change specific configuration by editing the file `/srv/prunner/.config/peertube-runner-nodejs/[id]/config.toml`.

::: info
For every peertube-runner commands described below, you have to run them as the `prunner` user.
So for example, to call the `list-registered` command: `sudo -u prunner peertube-runner list-registered`.
Otherwise the script will read the wrong configuration and cache files, and won't work as expected.
:::

### Register

Then, you can register the runner to process transcoding job of a remote PeerTube instance:

::: code-group

```bash [Shell]
peertube-runner register --url http://peertube.example.com --registration-token ptrrt-... --runner-name my-runner-name
```

```bash [Systemd]
sudo -u prunner peertube-runner register --url http://peertube.example.com --registration-token ptrrt-... --runner-name my-runner-name
```

:::

The runner will then use a websocket connection with the PeerTube instance to be notified about new available transcoding jobs.

### Unregister

To unregister a PeerTube instance:

::: code-group


```bash [Shell]
peertube-runner unregister --url http://peertube.example.com --runner-name my-runner-name
```

```bash [Systemd]
sudo -u prunner peertube-runner unregister --url http://peertube.example.com --runner-name my-runner-name
```

:::

### List registered instances

::: code-group

```bash [Shell]
peertube-runner list-registered
```

```bash [Systemd]
sudo -u prunner peertube-runner list-registered
```

:::

### List jobs

**Runner >= 0.1.0**

To list jobs that are processed by the runner:

::: code-group

```bash [Shell]
peertube-runner list-jobs
peertube-runner list-jobs --include-payload
```

```bash [Systemd]
sudo -u prunner peertube-runner list-jobs
sudo -u prunner peertube-runner list-jobs --include-payload
```

:::

### Graceful shutdown

Ask the runner to shutdown when it has finished all of its current tasks:

::: code-group

```bash [Shell]
peertube-runner graceful-shutdown
```

```bash [Systemd]
sudo -u prunner peertube-runner graceful-shutdown
```

:::

### Update the runner package

You can check if there is a new runner version using:

```bash
sudo npm outdated -g @peertube/peertube-runner
```

```
Package                    Current  Wanted  Latest  Location                                Depended by
@peertube/peertube-runner    0.0.6   0.0.7   0.0.7  node_modules/@peertube/peertube-runner  lib
```

To update the runner:

Update the package
```bash
sudo npm update -g @peertube/peertube-runner
```

Check that the version changed (optional)
```bash
sudo npm list -g @peertube/peertube-runner
```

Restart the service (if you are using systemd)
```bash
sudo systemctl restart prunner.service
```

## Server tools

Server tools are scripts that interact directly with the code of your PeerTube instance.
They must be run on the server, in `peertube-latest` directory.

### Parse logs

To parse PeerTube last log file:

::: code-group

```bash [Classic installation]
cd /var/www/peertube/peertube-latest; \
    sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run parse-log -- --level info
```

```bash [Docker]
cd /var/www/peertube-docker; \
    docker compose exec -u peertube peertube npm run parse-log -- --level info
```

:::

`--level` is optional and could be `info`/`warn`/`error`

You can also remove SQL or HTTP logs using `--not-tags`:

::: code-group

```bash [Classic installation]
cd /var/www/peertube/peertube-latest; \
    sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run parse-log -- --level debug --not-tags http sql
```

```bash [Docker]
cd /var/www/peertube-docker; \
    docker compose exec -u peertube peertube npm run parse-log -- --level debug --not-tags http sql
```

:::

### Regenerate video and playlist thumbnails

Regenerating local video and playlist thumbnails could be useful because new PeerTube releases may increase thumbnail sizes:

::: code-group

```bash [Classic installation]
cd /var/www/peertube/peertube-latest; \
    sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run regenerate-thumbnails
```

```bash [Docker]
cd /var/www/peertube-docker; \
    docker compose exec -u peertube peertube npm run regenerate-thumbnails
```

:::

### Add or replace specific video file

You can use this script to import a video file to replace an already uploaded file or to add a new web compatible resolution to a video. PeerTube needs to be running.
You can then create a transcoding job using the web interface if you need to optimize your file or create an HLS version of it.

::: code-group

```bash [Classic installation]
cd /var/www/peertube/peertube-latest; \
    sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run create-import-video-file-job -- -v [videoUUID] -i [videoFile]
```

```bash [Docker]
cd /var/www/peertube-docker; \
    docker compose exec -u peertube peertube npm run create-import-video-file-job -- -v [videoUUID] -i [videoFile]
```

:::

### Move video files from filesystem to object storage

Use this script to move video related files (video files, original video file, captions, etc.) to object storage.

::: code-group

```bash [Classic installation]
cd /var/www/peertube/peertube-latest; \
    sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run create-move-video-storage-job -- --to-object-storage -v [videoUUID]
```

```bash [Docker]
cd /var/www/peertube-docker; \
    docker compose exec -u peertube peertube npm run create-move-video-storage-job -- --to-object-storage -v [videoUUID]
```

:::

The script can also move all video related files that are not already in object storage:

::: code-group

```bash [Classic installation]
cd /var/www/peertube/peertube-latest; \
    sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run create-move-video-storage-job -- --to-object-storage --all-videos
```

```bash [Docker]
cd /var/www/peertube-docker; \
    docker compose exec -u peertube peertube npm run create-move-video-storage-job -- --to-object-storage --all-videos
```

:::

### Move video files from object storage to filesystem

**PeerTube >= 6.0**

Use this script to move video related files (video files, original video file, captions, etc.) from object storage to the PeerTube instance filesystem.

::: code-group

```bash [Classic installation]
cd /var/www/peertube/peertube-latest; \
    sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run create-move-video-storage-job -- --to-file-system -v [videoUUID]
```

```bash [Docker]
cd /var/www/peertube-docker; \
    docker compose exec -u peertube peertube npm run create-move-video-storage-job -- --to-file-system -v [videoUUID]
```

:::

The script can also move all video related files that are not already on the filesystem:

::: code-group

```bash [Classic installation]
cd /var/www/peertube/peertube-latest; \
    sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run create-move-video-storage-job -- --to-file-system --all-videos
```

```bash [Docker]
cd /var/www/peertube-docker; \
    docker compose exec -u peertube peertube npm run create-move-video-storage-job -- --to-file-system --all-videos
```

:::

### Cleanup remote files

**PeerTube >= 6.2**

Use this script to recover disk space by removing remote files (thumbnails, avatars...) that can be re-fetched later by your PeerTube instance on-demand.

Restart PeerTube after running this script.

::: code-group

```bash [Classic installation]
cd /var/www/peertube/peertube-latest; \
    sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run house-keeping -- --delete-remote-files
```

```bash [Docker]
cd /var/www/peertube-docker; \
    docker compose exec -u peertube peertube npm run house-keeping -- --delete-remote-files
```

:::


### Generate storyboard

**PeerTube >= 6.0**

Use this script to generate storyboard of a specific video:

::: code-group

```bash [Classic installation]
cd /var/www/peertube/peertube-latest; \
    sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run create-generate-storyboard-job -- -v [videoUUID]
```

```bash [Docker]
cd /var/www/peertube-docker; \
    docker compose exec -u peertube peertube npm run create-generate-storyboard-job -- -v [videoUUID]
```

:::

The script can also generate all missing storyboards of local videos:

::: code-group

```bash [Classic installation]
cd /var/www/peertube/peertube-latest; \
    sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run create-generate-storyboard-job -- --all-videos
```

```bash [Docker]
cd /var/www/peertube-docker; \
    docker compose exec -u peertube peertube npm run create-generate-storyboard-job -- --all-videos
```

:::

### Prune filesystem/object storage

Some transcoded videos or shutdown at a bad time can leave some unused files on your storage.
To delete these files (a confirmation will be demanded first):

::: code-group

```bash [Classic installation]
cd /var/www/peertube/peertube-latest; \
    sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run prune-storage
```

```bash [Docker]
cd /var/www/peertube-docker; \
    docker compose exec -u peertube peertube npm run prune-storage
```

:::

It's also possible to remove more local files if your stop PeerTube using the `--offline` option:

::: code-group

```bash [Classic installation]
cd /var/www/peertube/peertube-latest; \
    sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run prune-storage -- --offline
```

```bash [Docker]
cd /var/www/peertube-docker; \
    docker compose exec -u peertube peertube npm run prune-storage -- --offline
```

:::

### Update PeerTube instance domain name

**Changing the hostname is unsupported and may be a risky operation, especially if you have already federated.**
If you started PeerTube with a domain, and then changed it you will have
invalid torrent files and invalid URLs in your database. To fix this, you have
to run the command below (keep in mind your follower instances will NOT update their URLs).

::: code-group

```bash [Classic installation]
cd /var/www/peertube/peertube-latest; \
    sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run update-host
```

```bash [Docker]
cd /var/www/peertube-docker; \
    docker compose exec -u peertube peertube npm run update-host
```

:::

### Reset user password

To reset a user password from CLI, run:

::: code-group

```bash [Classic installation]
cd /var/www/peertube/peertube-latest; \
    sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run reset-password -- -u target_username
```

```bash [Docker]
cd /var/www/peertube-docker; \
    docker compose exec -u peertube peertube npm run reset-password -- -u target_username
```

:::


### Install or uninstall plugins

The difference with `peertube plugins` CLI is that these scripts can be used even if PeerTube is not running.
If PeerTube is running, you need to restart it for the changes to take effect (whereas with `peertube plugins` CLI, plugins/themes are dynamically loaded on the server).

To install/update a plugin or a theme from the disk:

::: code-group

```bash [Classic installation]
cd /var/www/peertube/peertube-latest; \
    sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run plugin:install -- --plugin-path /local/plugin/path
```

```bash [Docker]
cd /var/www/peertube-docker; \
    docker compose exec -u peertube peertube npm run plugin:install -- --plugin-path /local/plugin/path
```

:::

From NPM:

::: code-group

```bash
cd /var/www/peertube/peertube-latest; \
    sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run plugin:install -- --npm-name peertube-plugin-myplugin
```

```bash [Docker]
cd /var/www/peertube-docker; \
    docker compose exec -u peertube peertube npm run plugin:install -- --npm-name peertube-plugin-myplugin
```

:::

To uninstall a plugin or a theme:

::: code-group

```bash [Classic installation]
cd /var/www/peertube/peertube-latest; \
    sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run plugin:uninstall -- --npm-name peertube-plugin-myplugin
```

```bash [Docker]
cd /var/www/peertube-docker; \
    docker compose exec -u peertube peertube npm run plugin:uninstall -- --npm-name peertube-plugin-myplugin
```

:::

---

### Support Doc Translation (`support/doc/translation.md`)

# Translation

We use [Weblate](https://weblate.org) as translation platform.
Please do not edit translation files directly from Git, you have to use Weblate!

If you don't see your locale in the platform you can add it directly in the Weblate interface.
Then, if you think there are enough translated strings, please [create an issue](https://github.com/Chocobozzz/PeerTube/issues) so we add the new locale in PeerTube!

Translations are manually pulled and merged in PeerTube software and are publicly available in the next official release.
You can get a chance to see translations before the official release by going to https://peertube2.cpy.re which is updated every night with the latest PeerTube changes.


## How to

 * Create an account: https://weblate.framasoft.org/accounts/register/
 * Validate your email and follow the link sent
 * Create your password (keep the `Current password` field empty) and set up your account
 * To translate the PeerTube web, visit the PeerTube project page: https://weblate.framasoft.org/projects/peertube/
 * To translate the PeerTube mobile application, visit the PeerTube App project page: https://weblate.framasoft.org/projects/peertube-app/
 * Choose the file and the locale you want to translate


## Files

There are 4 files:
 * **angular**: contains client strings
 * **player**: contains player strings.
 Most of the strings come from VideoJS, so you can help yourself by using [video.js JSON files](https://github.com/videojs/video.js/tree/master/lang)
 * **server**: contains server strings clients can fetch in JSON format so they don't have to translate common PeerTube strings themselves (iso639 languages, privacies, licences...)
 * **server-internal**: contains internal server strings used in the REST API responses or emails


## Tips

### Special tags

You must not translate special tags like `<x id="INTERPOLATION" ... />`.

For example:
```
<x id="INTERPOLATION" equiv-text="{{ video.publishedAt | myFromNow }}"/> - <x id="INTERPOLATION_1" equiv-text="{{ video.views | myNumberFormatter }}"/> views
```

should be in French
```
<x id="INTERPOLATION" equiv-text="{{ video.publishedAt | myFromNow }}"/> - <x id="INTERPOLATION_1" equiv-text="{{ video.views | myNumberFormatter }}"/> vues
```


### Singular/plural

For singular/plural translations, you must translate values inside `{` and `}`. **Please don't translate the word *other***

For example:

```
{VAR_PLURAL, plural, =0 {No videos} =1 {1 video} other {<x id="INTERPOLATION" equiv-text="{{ playlist.videosLength }}"/> videos} }
```

should be in French

```
{VAR_PLURAL, plural, =0 {Aucune vidéo} =1 {1 vidéo} other {<x id="INTERPOLATION" equiv-text="{{ playlist.videosLength }}"/> vidéos} }
```

---

### Support Doc Api Embeds (`support/doc/api/embeds.md`)

# PeerTube Embed API

PeerTube lets you embed videos and programmatically control their playback. This documentation covers how to interact with the PeerTube Embed API.

## Playground

Any PeerTube embed URL (ie `https://my-instance.example.com/videos/embed/52a10666-3a18-4e73-93da-e8d3c12c305a`) can be viewed as an embedding playground which
allows you to test various aspects of PeerTube embeds. Simply replace `/embed` with `/test-embed` and visit the URL in a browser.
For instance, the playground URL for the above embed URL is `https://my-instance.example.com/videos/test-embed/52a10666-3a18-4e73-93da-e8d3c12c305a`.

## Quick Start

Given an existing PeerTube embed `<iframe>` **with API enabled** (`https://my-instance.example.com/videos/embed/52a10666-3a18-4e73-93da-e8d3c12c305a?api=1`),
one can use the PeerTube Embed API to control it by first including the library. You can include it via NPM with:

```
npm install @peertube/embed-api
```

Now just use the `PeerTubePlayer` class exported by the module:

```typescript
import { PeerTubePlayer } from '@peertube/embed-api.js'

...
```

Or use the minified build from NPM CDN in your HTML file:

```
<script src="https://unpkg.com/@peertube/embed-api/build/player.min.js"></script>

<script>
  const PeerTubePlayer = window['PeerTubePlayer']

  ...
</script>
```

Then you can instantiate the player:

```typescript
let player = new PeerTubePlayer(document.querySelector('iframe'))
await player.ready // wait for the player to be ready

// now you can use it!
player.play()
player.seek(32)
player.pause()
```

## Embed URL parameters

You can customize PeerTube player by specifying URL query parameters.
For example `https://my-instance.example.com/videos/embed/52a10666-3a18-4e73-93da-e8d3c12c305a?start=1s&stop=18s&loop=1&autoplay=1&muted=1&warningTitle=0&controlBar=0&peertubeLink=0&p2p=0`

### start

Start the video at a specific time.
Value must be raw seconds or a duration (`3m4s`)
Default: starts at `0`

### stop

Stop the video at a specific time.
Value must be raw seconds or a duration (`54s`)
Default: ends at content end

### controls

Mimics video HTML element `controls` attribute, meaning that all controls (including big play button, control bar, etc.) will be removed.
It can be useful if you want to have a full control of the PeerTube player.

Value must be `0` or `1`.
Default: `1`

### controlBar

Hide control bar when the video is played.

Value must be `0` or `1`.
Default: `1`

### peertubeLink

Hide PeerTube instance link in control bar.

Value must be `0` or `1`.
Default: `1`

### muted

Mute the video by default.

Value must be `0` or `1`.
Default: tries to restore the last muted setting set by the user

### loop

Automatically start again the video when it ends.

Value must be `0` or `1`.
Default: `0`

### subtitle

Auto select a subtitle by default.

Value must be a valid subtitle ISO code (`fr`, `en`, etc.).
Default: no subtitle selected and then tries to restore the last subtitle set by the user

### autoplay

Try to automatically play the video.
Most web browsers disable video autoplay if the user did not interact with the video. You can try to bypass this limitation by muting the video.

Value must be `0` or `1`.
Default: `0`

### playbackRate

Force the default playback rate (`0.75`, `1.5` etc).
Default: `1`

### title

Show/Hide embed title.

Value must be `0` or `1`.
Default: `1`

### warningTitle

Show/Hide P2P warning title.

Value must be `0` or `1`.
Default: `1`

### p2p

Enable/Disable P2P.

Value must be `0` or `1`.
Default: tries to use the user setting and fallbacks to instance setting if user setting is not found

### bigPlayBackgroundColor

Customize big play button background color.

Value must be a valid color (`red` or `rgba(100, 100, 100, 0.5)`).
Default: rgba(0, 0, 0, 0.8)

### foregroundColor

Customize embed font color.

Value must be a valid color (`red` or `rgba(100, 100, 100, 0.5)`).

Default: `white`

### mode

Force a specific player engine.

Value must be a valid mode (`web-video` or `p2p-media-loader`).

See behaviour description [here](https://docs.joinpeertube.org/admin/configuration#vod-transcoding)

Default: `p2p-media-loader` and fallback to `web-video` mode.


### playlistPosition

If you are embedding a playlist, select the video to play by specifying its position.

Value must be a number.

Default: `1`

### api

Enable/Disable embed JavaScript API (see methods below).

Value must be `0` or `1`.

Default: `0`

### waitPasswordFromEmbedAPI

**PeerTube >= 6.0**

If the video requires a password, PeerTube will wait a password provided by `setVideoPassword` method before loading the video.

Until you provide a password, `player.ready` is not resolved.

Value must be `0` or `1`.

Default: `0`


## Embed attributes

### `ready: Promise<void>`

This promise is resolved when the video is loaded and the player is ready.


## Embed methods

### `isPlaying(): Promise<boolean>`

**PeerTube >= 7.0**

Check if the player is playing the media.

### `play(): Promise<void>`

Starts playback, or resumes playback if it is paused.

### `pause(): Promise<void>`

Pauses playback.

### `getCurrentTime(): Promise<number>`

**PeerTube >= 7.0**

Get player current time in seconds.

### `seek(positionInSeconds : number): Promise<void>`

Seek to the given position, as specified in seconds into the video.

### `addEventListener(eventName : string, handler : Function)`

Add a listener for a specific event. See below for the available events.

### `removeEventListener(eventName : string, handler : Function)`

Remove a listener.

### `getResolutions() : Promise<PeerTubeResolution[]>`

Get the available resolutions. A `PeerTubeResolution` looks like:

```json
{
    "id": 3,
    "label": "720p",
    "height": "720",
    "active": true
}
```

`active` is true if the resolution is the currently selected resolution.

### `setResolution(resolutionId : number): Promise<void>`

Change the current resolution. Pass `-1` for automatic resolution (when available).
Otherwise, `resolutionId` should be the ID of an object returned by `getResolutions()`

### `getPlaybackRates() : Promise<number[]>`

Get the available playback rates, where `1` represents normal speed, `0.5` is half speed, `2` is double speed, etc.

### `getPlaybackRate() : Promise<number>`

Get the current playback rate. See `getPlaybackRates()` for more information.

### `setPlaybackRate(rate: number) : Promise<void>`

Set the current playback rate. The passed rate should be a value as returned by `getPlaybackRates()`.

### `setVolume(factor: number) : Promise<void>`

Set the playback volume. Value should be between `0` and `1`.

### `getVolume(): Promise<number>`

Get the playback volume. Returns a value between `0` and `1`.

### `setCaption(id: string) : Promise<void>`

Update current caption using the caption id.

### `getCaptions(): Promise<{ id: string, label: string, src: string, mode: 'disabled' | 'showing' }>`

Get video captions.

### `playNextVideo(): Promise<void>`

Play next video in playlist.

### `playPreviousVideo(): Promise<void>`

Play previous video in playlist.

### `getCurrentPosition(): Promise<void>`

Get current position in playlist (starts from 1).


### `setVideoPassword(): Promise<void>`

**PeerTube >= 6.0**

Set the video password so the user doesn't have to manually fill it.
`waitPasswordFromEmbedAPI=1` is required in embed URL.


### `getImageDataUrl(): Promise<string>`

**PeerTube >= 6.2**

Get the current frame as JPEG image data URL.


## Embed events

You can subscribe to events by using `addEventListener()`. See above for details.

### Event `playbackStatusUpdate`

Fired every half second to provide the current status of playback.
The parameter of the callback will resemble:

```json
{
  "position": 22.3,
  "volume": 0.9,
  "duration": "171.37499",
  "playbackState": "playing"
}
```

`duration` field and `ended` `playbackState` are available in PeerTube >= 2.2.

The `volume` field contains the volume from `0` (silent) to `1` (full volume).
The `playbackState` can be `unstarted`, `playing`, `paused` or `ended`. More states may be added later.

### Event `playbackStatusChange`

Fired when playback transitions between states, such as `paused` and `playing`. More states may be added later.

### Event `resolutionUpdate`

Fired when the available resolutions have changed, or when the currently selected resolution has changed. Listener should call `getResolutions()` to get the updated information.

### Event `volumeChange`

Fired when the player volume changed.

---

### Support Doc Api Openapi.Yaml (`support/doc/api/openapi.yaml`)

openapi: 3.0.3
info:
  title: PeerTube
  version: 8.3.0
  contact:
    name: PeerTube Community
    url: https://joinpeertube.org
  license:
    name: AGPLv3.0
    url: https://github.com/Chocobozzz/PeerTube/blob/master/LICENSE
  x-logo:
    url: https://joinpeertube.org/img/brand.png
    altText: PeerTube Project Homepage
  description: |
    The PeerTube API is built on HTTP(S) and is RESTful. You can use your favorite
    HTTP/REST library for your programming language to use PeerTube.

    See the [REST API quick start](https://docs.joinpeertube.org/api/rest-getting-started) for a few
    examples of using the PeerTube API.

    # Authentication

    When you sign up for an account on a PeerTube instance, you are given the possibility
    to generate sessions on it, and authenticate there using an access token. Only __one
    access token can currently be used at a time__.

    ## Roles

    Accounts are given permissions based on their role. There are three roles on
    PeerTube: Administrator, Moderator, and User. See the [roles guide](https://docs.joinpeertube.org/admin/managing-users#roles) for a detail of their permissions.

    # Errors

    The API uses standard HTTP status codes to indicate the success or failure
    of the API call, completed by a [RFC7807-compliant](https://tools.ietf.org/html/rfc7807) response body.

    ```
    HTTP 1.1 404 Not Found
    Content-Type: application/problem+json; charset=utf-8

    {
      "detail": "Video not found",
      "docs": "https://docs.joinpeertube.org/api-rest-reference.html#operation/getVideo",
      "status": 404,
      "title": "Not Found",
      "type": "about:blank"
    }
    ```

    We provide error `type` (following RFC7807) and `code` (internal PeerTube code) values for [a growing number of cases](https://github.com/Chocobozzz/PeerTube/blob/develop/packages/models/src/server/server-error-code.enum.ts),
    but it is still optional. Types are used to disambiguate errors that bear the same status code
    and are non-obvious:

    ```
    HTTP 1.1 403 Forbidden
    Content-Type: application/problem+json; charset=utf-8

    {
      "detail": "Cannot get this video regarding follow constraints",
      "docs": "https://docs.joinpeertube.org/api-rest-reference.html#operation/getVideo",
      "status": 403,
      "title": "Forbidden",
      "type": "https://docs.joinpeertube.org/api-rest-reference.html#section/Errors/does_not_respect_follow_constraints"
    }
    ```

    Here a 403 error could otherwise mean that the video is private or blocklisted.

    ## Validation errors

    Example:

    ```
    HTTP 1.1 400 Bad Request
    Content-Type: application/problem+json; charset=utf-8

    {
      "detail": "Incorrect request parameters: id",
      "docs": "https://docs.joinpeertube.org/api-rest-reference.html#operation/getVideo",
      "instance": "/api/v1/videos/9c9de5e8-0a1e-484a-b099-e80766180",
      "invalid-params": {
        "id": {
          "location": "params",
          "msg": "Invalid value",
          "param": "id",
          "value": "9c9de5e8-0a1e-484a-b099-e80766180"
        }
      },
      "status": 400,
      "title": "Bad Request",
      "type": "about:blank"
    }
    ```

    Where `id` is the name of the field concerned by the error, within the route definition.
    `invalid-params.<field>.location` can be either 'params', 'body', 'header', 'query' or 'cookies'.
    `invalid-params.<field>.value` reports the value that didn't pass validation whose `invalid-params.<field>.msg` is about.

    ## max_file_size_reached

    The uploaded file exceeds the instance-wide file size limit.

    ## quota_reached

    The uploaded file exceeds the user's storage quota.

    ## does_not_respect_follow_constraints

    The requested remote resource cannot be accessed because the instance does not follow its origin.

    ## live_not_enabled

    Live streaming is not enabled on the instance.

    ## live_not_allowing_replay

    Saving live replays is disabled on this instance, so a live cannot be created or updated with `saveReplay` enabled.

    ## live_conflicting_permanent_and_save_replay

    Not returned by PeerTube anymore: permanent lives can save replays.

    ## max_instance_lives_limit_reached

    The instance has reached its maximum number of simultaneous live streams.

    ## max_user_lives_limit_reached

    The user has reached the maximum number of simultaneous live streams.

    ## incorrect_files_in_torrent

    The torrent does not contain exactly one usable video file.

    ## comment_not_associated_to_video

    The comment is not associated with the requested video.

    ## invalid_grant

    The OAuth grant or refresh token is invalid.

    ## invalid_client

    Client authentication failed.

    ## invalid_token

    The access token is expired, revoked, malformed, or otherwise invalid.

    ## unauthorized_request

    The endpoint requires authentication but no access token was provided.

    ## invalid_request

    The authentication or token request is malformed: missing `grant_type`, malformed `Authorization` header,
    access token sent using more than one method, or sent in the query string.

    ## unsupported_grant_type

    The `grant_type` is not supported. PeerTube supports `password` and `refresh_token`.

    ## unauthorized_client

    The OAuth client is not allowed to use the requested `grant_type`.

    ## server_error

    An unexpected error occurred while checking the access token.

    ## missing_two_factor

    The required two-factor authentication header is missing.

    ## too_long_password

    The password exceeds the maximum allowed length.

    ## invalid_two_factor

    The two-factor authentication code is invalid.

    ## account_blocked

    The account is blocked.

    ## email_not_verified

    The account email address has not been verified.

    ## account_waiting_for_approval

    The account is waiting for administrator approval.

    ## account_approval_rejected

    The account approval request was rejected.

    ## runner_job_not_in_processing_state

    The runner job is not in the processing state.

    ## runner_job_not_in_pending_state

    The runner job is not in the pending state.

    ## unknown_runner_token

    The runner token is unknown.

    ## video_requires_password

    A password is required to access the video.

    ## incorrect_video_password

    The password provided for the video is incorrect.

    ## video_already_being_transcoded

    The video is already being transcoded.

    ## video_already_being_transcribed

    The video is already being transcribed.

    ## video_already_has_captions

    The video already has captions.

    ## max_user_video_quota_exceeded_for_user_export

    The user requested an export including video files, but the total size of their videos is above the maximum allowed by the instance for such exports.
    Request an export without video files instead.

    ## current_password_is_invalid

    The current password is invalid.

    ## current_password_is_missing

    The action requires a [password confirmation](#section/Password-confirmation) but `currentPassword` is missing.

    ## password_confirmation_unavailable

    The action requires a [password confirmation](#section/Password-confirmation) but the user authenticates with an external auth plugin (OpenID Connect, SAML...), so PeerTube cannot check their password.

    # Rate limits

    We are rate-limiting all endpoints of PeerTube's API. Custom values can be set by administrators:

    | Endpoint (prefix: `/api/v1`) | Calls         | Time frame   |
    |------------------------------|---------------|--------------|
    | `/*`                         | 50            | 10 seconds   |
    | `POST /users/token`          | 15            | 5 minutes    |
    | `POST /users/register`       | 2<sup>*</sup> | 5 minutes    |
    | `POST /users/ask-send-verify-email` | 3      | 5 minutes    |

    Depending on the endpoint, <sup>*</sup>failed requests are not taken into account. A service
    limit is announced by a `429 Too Many Requests` status code.

    You can get details about the current state of your rate limit by reading the
    following headers:

    | Header                  | Description                                                |
    |-------------------------|------------------------------------------------------------|
    | `X-RateLimit-Limit`     | Number of max requests allowed in the current time period  |
    | `X-RateLimit-Remaining` | Number of remaining requests in the current time period    |
    | `X-RateLimit-Reset`     | Timestamp of end of current time period as UNIX timestamp  |
    | `Retry-After`           | Seconds to delay after the first `429` is received         |

    # Password confirmation

    If the `webadmin.password_confirmation.enabled` setting is enabled (default), sensitive administrator actions require
    the user password in the `currentPassword` field of the request body:

      - Install or update a plugin/theme
      - Change the custom JavaScript or CSS of the instance (`instance.customizations` of the custom configuration)
      - Create an administrator, or give the administrator role to a user
      - Change the password, email or auth plugin (`pluginAuth`) of an administrator

    After 10 failed password confirmations in 10 minutes (configurable), the user receives a `429 Too Many Requests` status code
    until the end of the time frame, even with the correct password.

    # CORS

    This API features [Cross-Origin Resource Sharing (CORS)](https://fetch.spec.whatwg.org/),
    allowing cross-domain communication from the browser for some routes:

    | Endpoint                    |
    |------------------------- ---|
    | `/api/*`                    |
    | `/download/*`               |
    | `/lazy-static/*`            |
    | `/.well-known/webfinger`    |

    In addition, all routes serving ActivityPub are CORS-enabled for all origins.
externalDocs:
  url: https://docs.joinpeertube.org/api-rest-reference.html
tags:
  - name: Register
    description: |
      As a visitor, you can use this API to open an account (if registrations are open on
      that PeerTube instance). As an admin, you should use the dedicated [User creation
      API](#operation/addUser) instead.
  - name: Session
    x-displayName: Login/Logout
    description: |
      Sessions deal with access tokens over time. Only __one session token can currently be used at a time__.
  - name: Accounts
    description: >
      Accounts encompass remote accounts discovered across the federation,
      and correspond to the main Actor, along with video channels a user can create, which
      are also Actors.

      When a comment is posted, it is done with your Account's Actor.
  - name: Users
    description: >
      Using some features of PeerTube require authentication, for which User
      provide different levels of permission as well as associated user
      information. Each user has a corresponding local Account for federation.
  - name: User Exports
    description: >
      To create an archive of user data.
  - name: User Imports
    description: >
      To import an archive of user data.
  - name: My User
    description: >
      Operations related to your own User, when logged-in.
  - name: My Subscriptions
    description: >
      Operations related to your subscriptions to video channels, their
      new videos, and how to keep up to date with their latest publications!
  - name: My History
    description: >
      Operations related to your watch history.
  - name: My Notifications
    description: >
      Notifications following new videos, follows or reports. They allow you
      to keep track of the interactions and overall important information that
      concerns you. You MAY set per-notification type delivery preference, to
      receive the info either by mail, by in-browser notification or both.
  - name: Config
    description: >
      Each server exposes public information regarding supported videos and
      options.
  - name: Job
    description: >
      Jobs are long-running tasks enqueued and processed by the instance
      itself. No additional worker registration is currently available.
  - name: Instance Follows
    description: >
      Managing servers which the instance interacts with is crucial to the
      concept of federation in PeerTube and external video indexation. The PeerTube
      server then deals with inter-server ActivityPub operations and propagates
      information across its social graph by posting activities to actors' inbox
      endpoints.
    externalDocs:
      url: https://docs.joinpeertube.org/admin/following-instances#instances-follows
  - name: Instance Redundancy
    description: >
      Redundancy is part of the inter-server solidarity that PeerTube fosters.
      Manage the list of instances you wish to help by seeding their videos according
      to the policy of video selection of your choice. Note that you have a similar functionality
      to mirror individual videos, see [video mirroring](#tag/Video-Mirroring).
    externalDocs:
      url: https://docs.joinpeertube.org/admin/following-instances#instances-redundancy
  - name: Plugins
    description: >
      Managing plugins installed from a local path or from NPM, or search for new ones.
    externalDocs:
      url: https://docs.joinpeertube.org/api/plugins
  - name: Abuses
    description: |
      Abuses deal with reports of local or remote videos/comments/accounts alike.
  - name: Video
    description: |
      Operations dealing with listing, uploading, fetching or modifying videos.
  - name: Video Upload
    description: |
      Operations dealing with adding video or audio. PeerTube supports two upload modes, and three import modes.

      ### Upload

      - [_legacy_](#operation/uploadLegacy), where the video file is sent in a single request
      - [_resumable_](#operation/uploadResumableInit), where the video file is sent in chunks

      You can upload videos more reliably by using the resumable variant. Its protocol lets
      you resume an upload operation after a network interruption or other transmission failure,
      saving time and bandwidth in the event of network failures.

      Favor using resumable uploads in any of the following cases:
      - You are transferring large files
      - The likelihood of a network interruption is high
      - Uploads are originating from a device with a low-bandwidth or unstable Internet connection, such as a mobile device

      ### Import

      - _URL_-based: where the URL points to any service supported by [youtube-dl](https://ytdl-org.github.io/youtube-dl/)
      - _magnet_-based: where the URI resolves to a BitTorrent resource containing a single supported video file
      - _torrent_-based: where the metainfo file resolves to a BitTorrent resource containing a single supported video file

      The import function is practical when the desired video/audio is available online. It makes PeerTube
      download it for you, saving you as much bandwidth and avoiding any instability or limitation your network might have.
  - name: Video Imports
    description: Operations dealing with listing, adding and removing video imports.
  - name: Channels Sync
    description: Operations dealing with synchronizing PeerTube user's channel with channels of other platforms
  - name: Video Captions
    description: Operations dealing with listing, adding and removing closed captions of a video.
  - name: Video Chapters
    description: Operations dealing with managing chapters of a video.
  - name: Video Channels
    description: Operations dealing with the creation, modification and listing of videos within a channel.
  - name: Player Settings
    description: Operations dealing with video player settings for videos and channels.
  - name: Video Comments
    description: >
      Operations dealing with comments to a video. Comments are organized in threads: adding a
      comment in response to the video starts a thread, adding a reply to a comment adds it to
      its root comment thread.
  - name: Video Blocks
    description: Operations dealing with blocking videos (removing them from view and preventing interactions).
  - name: Automatic Tags
    description: Automatic tags set on objects (like comments or videos) by specific rules (external link, watched words, etc.)
  - name: Watched Words
    description: Manage list of watched words to detect patterns on objects (like comments of videos)
  - name: Video Rates
    description: Like/dislike a video.
  - name: Video Playlists
    description: Operations dealing with playlists of videos. Playlists are bound to users and/or channels.
  - name: Video Files
    description: Operations on video files
  - name: Video Transcoding
    description: Video transcoding related operations
  - name: Video Stats
    description: Video statistics
  - name: Video Feeds
    description: Server syndication feeds of videos
  - name: Video Download
    description: Download video files
  - name: Logs
    description: Operations dealing with client, server and audit logs.
  - name: Search
    description: |
      The search helps to find _videos_ or _channels_ from within the instance and beyond.
      Videos from other instances federated by the instance (that is, instances
      followed by the instance) can be found via keywords and other criteria of
      the advanced search.

      Administrators can also enable the use of a remote search system, indexing
      videos and channels that may not be federated by the instance.
  - name: Homepage
    description: Get and update the custom homepage
  - name: Video Mirroring
    description: |
      PeerTube instances can mirror videos from one another, and help distribute some videos.

      For importing videos as your own, refer to [video imports](#operation/importVideo).
  - name: Stats
    description: |
      Statistics
  - name: Contact
    description: Send a message to the instance administrators.
  - name: Debug
    description: Administrative debug endpoints.
  - name: Runner Registration Token
    description: |
      Manage runner registration tokens.
  - name: Runner Jobs
    description: Manage runner jobs and runner-side job execution.
  - name: Runners
    description: Register, list and remove remote runners.
  - name: Video Passwords
    description: Operations on video passwords.
  - name: Client Config
    description: Configuration of the web client.

x-tagGroups:
  - name: Static endpoints
    tags:
      - Static Video Files
  - name: Download
    tags:
      - Video Download
  - name: Feeds
    tags:
      - Video Feeds
  - name: Auth
    tags:
      - Register
      - Session
  - name: Accounts
    tags:
      - Accounts
      - Users
      - User Exports
      - User Imports
      - My User
      - My Subscriptions
      - My Notifications
      - My History
  - name: Videos
    tags:
      - Video
      - Video Upload
      - Video Imports
      - Video Captions
      - Video Chapters
      - Video Channels
      - Video Comments
      - Video Rates
      - Video Playlists
      - Video Stats
      - Ownership Change
      - Video Mirroring
      - Video Files
      - Video Transcoding
      - Live Videos
      - Channels Sync
      - Video Passwords
      - Video Embed Privacy
  - name: Search
    tags:
      - Search
  - name: Moderation
    tags:
      - Abuses
      - Video Blocks
      - Account Blocklist
      - Server Blocklist
      - Automatic Tags
      - Watched Words
  - name: Instance
    tags:
      - Config
      - Client Config
      - Homepage
      - Instance Follows
      - Instance Redundancy
      - Plugins
      - Stats
      - Logs
      - Job
  - name: Remote Jobs
    tags:
      - Runner Registration Token
      - Runner Jobs
      - Runners

paths:
  '/static/web-videos/{filename}':
    get:
      tags:
        - Static Video Files
      summary: Get public Web Video file
      description: "**PeerTube >= 6.0**"
      parameters:
        - $ref: '#/components/parameters/staticFilename'
      responses:
        '200':
          description: successful operation
        '404':
          description: not found
  '/static/web-videos/private/{filename}':
    get:
      tags:
        - Static Video Files
      summary: Get private Web Video file
      description: "**PeerTube >= 6.0**"
      parameters:
        - $ref: '#/components/parameters/staticFilename'
        - $ref: '#/components/parameters/videoFileToken'
      security:
        - OAuth2: []
      responses:
        '200':
          description: successful operation
        '403':
          description: invalid auth
        '404':
          description: not found

  '/static/streaming-playlists/hls/{filename}':
    get:
      tags:
        - Static Video Files
      summary: Get public HLS video file
      parameters:
        - $ref: '#/components/parameters/staticFilename'
      security:
        - OAuth2: []
      responses:
        '200':
          description: successful operation
        '403':
          description: invalid auth
        '404':
          description: not found
  '/static/streaming-playlists/hls/private/{filename}':
    get:
      tags:
        - Static Video Files
      summary: Get private HLS video file
      parameters:
        - $ref: '#/components/parameters/staticFilename'
        - $ref: '#/components/parameters/videoFileToken'
        - $ref: '#/components/parameters/reinjectVideoFileToken'
      security:
        - OAuth2: []
      responses:
        '200':
          description: successful operation
        '403':
          description: invalid auth
        '404':
          description: not found

  '/download/videos/generate/{videoIdOrUUID}':
    get:
      tags:
        - Video Download
      summary: Download video file
      description: Generate a mp4 container that contains at most 1 video stream and at most 1 audio stream.
        Mainly used to merge the HLS audio only video file and the HLS video only resolution file.
      parameters:
        - $ref: '#/components/parameters/videoIdOrUUID'
        - name: videoFileIds
          in: query
          required: true
          description: streams of video files to mux in the output
          schema:
            type: array
            items:
              type: integer
        - $ref: '#/components/parameters/videoFileToken'
      responses:
        '200':
          description: successful operation

  '/feeds/video-comments.{format}':
    get:
      tags:
        - Video Feeds
      summary: Comments on videos feeds
      operationId: getSyndicatedComments
      parameters:
        - name: format
          in: path
          required: true
          description: 'format expected (we focus on making `rss` the most feature-rich ; it serves [Media RSS](https://www.rssboard.org/media-rss))'
          schema:
            type: string
            enum:
              - xml
              - rss
              - rss2
              - atom
              - atom1
              - json
              - json1
        - name: videoId
          in: query
          description: 'limit listing comments to a specific video'
          schema:
            type: string
        - name: accountId
          in: query
          description: 'limit listing comments to videos of a specific account'
          schema:
            type: string
        - name: accountName
          in: query
          description: 'limit listing comments to videos of a specific account'
          schema:
            type: string
        - name: videoChannelId
          in: query
          description: 'limit listing comments to videos of a specific video channel'
          schema:
            type: string
        - name: videoChannelName
          in: query
          description: 'limit listing comments to videos of a specific video channel'
          schema:
            type: string
        - name: isLocal
          in: query
          required: false
          description: '**PeerTube >= 9.0** Display only comments of local or remote accounts'
          schema:
            type: boolean
        - name: onLocalVideo
          in: query
          required: false
          description: '**PeerTube >= 9.0** Display only comments of local or remote videos'
          schema:
            type: boolean
      responses:
        '200':
          description: successful operation
          headers:
            Cache-Control:
              schema:
                type: string
                default: 'max-age=900' # 15 min cache
          content:
            application/xml:
              schema:
                $ref: '#/components/schemas/VideoCommentsForXML'

              examples:
                nightly:
                  externalValue: https://peertube2.cpy.re/feeds/video-comments.xml?scope=local
            application/rss+xml:
              schema:
                $ref: '#/components/schemas/VideoCommentsForXML'
              examples:
                nightly:
                  externalValue: https://peertube2.cpy.re/feeds/video-comments.rss?scope=local
            text/xml:
              schema:
                $ref: '#/components/schemas/VideoCommentsForXML'
              examples:
                nightly:
                  externalValue: https://peertube2.cpy.re/feeds/video-comments.xml?scope=local
            application/atom+xml:
              schema:
                $ref: '#/components/schemas/VideoCommentsForXML'
              examples:
                nightly:
                  externalValue: https://peertube2.cpy.re/feeds/video-comments.atom?scope=local
            application/json:
              schema:
                type: object
              examples:
                nightly:
                  externalValue: https://peertube2.cpy.re/feeds/video-comments.json?scope=local
        '400':
          x-summary: field inconsistencies
          description: >
            Arises when:
              - videoId filter is mixed with a channel filter
        '404':
          description: video, video channel or account not found
        '406':
          description: accept header unsupported

  '/feeds/videos.{format}':
    get:
      tags:
        - Video Feeds
      summary: Common videos feeds
      operationId: getSyndicatedVideos
      parameters:
        - name: format
          in: path
          required: true
          description: 'format expected (we focus on making `rss` the most feature-rich ; it serves [Media RSS](https://www.rssboard.org/media-rss))'
          schema:
            type: string
            enum:
              - xml
              - rss
              - rss2
              - atom
              - atom1
              - json
              - json1
        - name: accountId
          in: query
          description: 'limit listing to a specific account'
          schema:
            type: string
        - name: accountName
          in: query
          description: 'limit listing to a specific account'
          schema:
            type: string
        - name: videoChannelId
          in: query
          description: 'limit listing to a specific video channel'
          schema:
            type: string
        - name: videoChannelName
          in: query
          description: 'limit listing to a specific video channel'
          schema:
            type: string
        - $ref: '#/components/parameters/sort'
        - $ref: '#/components/parameters/nsfw'
        - $ref: '#/components/parameters/isLocal'
        - $ref: '#/components/parameters/include'
        - $ref: '#/components/parameters/privacyOneOf'
        - $ref: '#/components/parameters/hasHLSFiles'
        - $ref: '#/components/parameters/hasWebVideoFiles'
      responses:
        '200':
          description: successful operation
          headers:
            Cache-Control:
              schema:
                type: string
                default: 'max-age=900' # 15 min cache
          content:
            application/xml:
              schema:
                $ref: '#/components/schemas/VideosForXML'
              examples:
                nightly:
                  externalValue: https://peertube2.cpy.re/feeds/videos.xml?scope=local
            application/rss+xml:
              schema:
                $ref: '#/components/schemas/VideosForXML'
              examples:
                nightly:
                  externalValue: https://peertube2.cpy.re/feeds/videos.rss?scope=local
            text/xml:
              schema:
                $ref: '#/components/schemas/VideosForXML'
              examples:
                nightly:
                  externalValue: https://peertube2.cpy.re/feeds/videos.xml?scope=local
            application/atom+xml:
              schema:
                $ref: '#/components/schemas/VideosForXML'
              examples:
                nightly:
                  externalValue: https://peertube2.cpy.re/feeds/videos.atom?scope=local
            application/json:
              schema:
                type: object
              examples:
                nightly:
                  externalValue: https://peertube2.cpy.re/feeds/videos.json?scope=local
        '404':
          description: video channel or account not found
        '406':
          description: accept header unsupported

  '/feeds/subscriptions.{format}':
    get:
      tags:
        - Video Feeds
      summary: Videos of subscriptions feeds
      operationId: getSyndicatedSubscriptionVideos
      parameters:
        - name: format
          in: path
          required: true
          description: 'format expected (we focus on making `rss` the most feature-rich ; it serves [Media RSS](https://www.rssboard.org/media-rss))'
          schema:
            type: string
            enum:
              - xml
              - rss
              - rss2
              - atom
              - atom1
              - json
              - json1
        - name: accountId
          in: query
          description: limit listing to a specific account
          schema:
            type: string
          required: true
        - name: token
          in: query
          description: private token allowing access
          schema:
            type: string
          required: true
        - $ref: '#/components/parameters/sort'
        - $ref: '#/components/parameters/nsfw'
        - $ref: '#/components/parameters/isLocal'
        - $ref: '#/components/parameters/include'
        - $ref: '#/components/parameters/privacyOneOf'
        - $ref: '#/components/parameters/hasHLSFiles'
        - $ref: '#/components/parameters/hasWebVideoFiles'
      responses:
        '200':
          description: successful operation
          headers:
            Cache-Control:
              schema:
                type: string
                default: 'max-age=900' # 15 min cache
          content:
            application/xml:
              schema:
                $ref: '#/components/schemas/VideosForXML'
            application/rss+xml:
              schema:
                $ref: '#/components/schemas/VideosForXML'
            text/xml:
              schema:
                $ref: '#/components/schemas/VideosForXML'
            application/atom+xml:
              schema:
                $ref: '#/components/schemas/VideosForXML'
            application/json:
              schema:
                type: object
        '406':
          description: accept header unsupported

  '/feeds/podcast/videos.xml':
    get:
      tags:
        - Video Feeds
      summary: Videos podcast feed
      operationId: getVideosPodcastFeed
      parameters:
        - name: videoChannelId
          in: query
          description: 'Limit listing to a specific video channel'
          required: false
          schema:
            type: string
        - name: playlistId
          in: query
          description: 'Limit listing to a specific video playlist'
          required: false
          schema:
            type: string
        - name: enclosurePreference
          in: query
          description: 'Filter enclosures by type (video-only or audio-only)'
          required: false
          schema:
            type: string
            enum:
              - video-only
              - audio-only
      responses:
        '200':
          description: successful operation
          headers:
            Cache-Control:
              schema:
                type: string
                default: 'max-age=900' # 15 min cache
        '404':
          description: video channel or playlist not found

  '/feeds/podcast/video-chapters.json':
    get:
      tags:
        - Video Feeds
      summary: Video chapters of podcast feeds
      description: |
        **PeerTube >= 9.0** Chapters of a video in the Podcasting 2.0 JSON format, referenced by the `podcast:chapters` tag of podcast feed items.
        See https://podcasting2.org/docs/podcast-namespace/tags/chapters
      operationId: getVideoPodcastChapters
      parameters:
        - name: videoId
          in: query
          description: 'The video id, uuid or short uuid'
          required: true
          schema:
            type: string
      responses:
        '200':
          description: successful operation
          content:
            application/json+chapters:
              schema:
                $ref: '#/components/schemas/PodcastChapters'
            application/json:
              schema:
                $ref: '#/components/schemas/PodcastChapters'
        '404':
          description: video not found
        '406':
          description: accept header unsupported

  '/api/v1/accounts/{name}':
    get:
      tags:
        - Accounts
      summary: Get an account
      operationId: getAccount
      parameters:
        - $ref: '#/components/parameters/name'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Account'
        '404':
          description: account not found

  '/api/v1/accounts/{name}/videos':
    get:
      tags:
        - Accounts
        - Video
      summary: 'List videos of an account'
      operationId: getAccountVideos
      parameters:
        - $ref: '#/components/parameters/name'
        # Common video filter parameters
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/skipCount'
        - $ref: '#/components/parameters/videosSort'
        - $ref: '#/components/parameters/nsfw'
        - $ref: '#/components/parameters/nsfwFlagsIncluded'
        - $ref: '#/components/parameters/nsfwFlagsExcluded'
        - $ref: '#/components/parameters/aiUsageOneOf'
        - $ref: '#/components/parameters/isLive'
        - $ref: '#/components/parameters/includeScheduledLive'
        - $ref: '#/components/parameters/categoryOneOf'
        - $ref: '#/components/parameters/licenceOneOf'
        - $ref: '#/components/parameters/languageOneOf'
        - $ref: '#/components/parameters/tagsOneOf'
        - $ref: '#/components/parameters/tagsAllOf'
        - $ref: '#/components/parameters/isLocal'
        - $ref: '#/components/parameters/include'
        - $ref: '#/components/parameters/hasHLSFiles'
        - $ref: '#/components/parameters/hasWebVideoFiles'
        - $ref: '#/components/parameters/host'
        - $ref: '#/components/parameters/autoTagOneOfVideo'
        - $ref: '#/components/parameters/stateOneOfVideo'
        - $ref: '#/components/parameters/privacyOneOf'
        - $ref: '#/components/parameters/excludeAlreadyWatched'
        - $ref: '#/components/parameters/search'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VideoListResponse'
      x-codeSamples:
        - lang: JavaScript
          source: |
            fetch('https://peertube2.cpy.re/api/v1/accounts/{name}/videos')
            .then(function(response) {
              return response.json()
            }).then(function(data) {
              console.log(data)
            })
        - lang: Shell
          source: |
            ## DEPENDENCIES: jq
            curl -s https://peertube2.cpy.re/api/v1/accounts/{name}/videos | jq
        - lang: Ruby
          source: |
            require 'net/http'
            require 'json'

            uri = URI.parse("https://peertube2.cpy.re/api/v1/accounts/{name}/videos")

            http = Net::HTTP.new(uri.host, uri.port)
            http.use_ssl = true

            response = http.get(uri.request_uri)

            puts JSON.parse(response.read_body)
        - lang: Python
          source: |
            import requests

            r = requests.get("https://peertube2.cpy.re/api/v1//accounts/{name}/videos")
            json = r.json()

            print(json)

  '/api/v1/accounts/{name}/followers':
    get:
      tags:
        - Accounts
      summary: 'List followers of an account'
      security:
        - OAuth2: []
      operationId: getAccountFollowers
      parameters:
        - $ref: '#/components/parameters/name'
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/followersSort'
        - $ref: '#/components/parameters/search'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  total:
                    type: integer
                    example: 1
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Follow'

  /api/v1/accounts:
    get:
      tags:
        - Accounts
      summary: List accounts
      operationId: getAccounts
      parameters:
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/sort'
      responses:
        '200':
          description: successful operation
          content:
            'application/json':
              schema:
                type: object
                properties:
                  total:
                    type: integer
                    example: 1
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Account'

  /api/v1/config:
    get:
      tags:
        - Config
      summary: Get instance public configuration
      operationId: getConfig
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ServerConfig'
              examples:
                nightly:
                  externalValue: https://peertube2.cpy.re/api/v1/config

  /api/v1/config/about:
    get:
      summary: Get instance "About" information
      description: |
        Translatable information is returned in the language of the request, using the `x-peertube-language` header
        or the `Accept-Language` header. If the instance has no translation for this language, the default information is returned.
      operationId: getAbout
      tags:
        - Config
      parameters:
        - name: x-peertube-language
          in: header
          required: false
          description: Locale of the web interface (`fr-FR`, `pt-BR`...) used to translate the instance information
          schema:
            type: string
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ServerConfigAbout'
              examples:
                nightly:
                  externalValue: https://peertube2.cpy.re/api/v1/config/about

  /api/v1/config/custom:
    get:
      summary: Get instance runtime configuration
      operationId: getCustomConfig
      tags:
        - Config
      security:
        - OAuth2:
          - admin
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ServerConfigCustom'
    put:
      summary: Set instance runtime configuration
      description: >
        Changing `instance.customizations.javascript` or `instance.customizations.css` requires a
        [password confirmation](#section/Password-confirmation): set `currentPassword` at the root of the request body.
      operationId: putCustomConfig
      tags:
        - Config
      security:
        - OAuth2:
          - admin
      responses:
        '200':
          description: successful operation
        '400':
          x-summary: field inconsistencies
          description: >
            Arises when:
              - the emailer is disabled and the instance is open to registrations
              - web videos and hls are disabled with transcoding enabled - you need at least one enabled
              - the custom JavaScript or CSS changed and `currentPassword` is missing
        '403':
          description: invalid `currentPassword`, or password confirmation unavailable for this user
        '429':
          description: too many failed password confirmations
    delete:
      summary: Delete instance runtime configuration
      operationId: delCustomConfig
      tags:
        - Config
      security:
        - OAuth2:
          - admin
      responses:
        '200':
          description: successful operation

  /api/v1/config/instance-banner/pick:
    post:
      summary: Update instance banner
      security:
        - OAuth2:
          - admin
      tags:
        - Config
      responses:
        '204':
          description: successful operation
        '413':
          description: image file too large
          headers:
            X-File-Maximum-Size:
              schema:
                type: string
                format: Nginx size
              description: Maximum file size for the banner
      requestBody:
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                bannerfile:
                  description: The file to upload.
                  type: string
                  format: binary
            encoding:
              bannerfile:
                contentType: image/png, image/jpeg

  '/api/v1/config/instance-banner':
    delete:
      summary: Delete instance banner
      security:
        - OAuth2:
          - admin
      tags:
        - Config
      responses:
        '204':
          description: successful operation

  /api/v1/config/instance-avatar/pick:
    post:
      summary: Update instance avatar
      security:
        - OAuth2:
          - admin
      tags:
        - Config
      responses:
        '204':
          description: successful operation
        '413':
          description: image file too large
          headers:
            X-File-Maximum-Size:
              schema:
                type: string
                format: Nginx size
              description: Maximum file size for the avatar
      requestBody:
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                avatarfile:
                  description: The file to upload.
                  type: string
                  format: binary
            encoding:
              avatarfile:
                contentType: image/png, image/jpeg

  '/api/v1/config/instance-avatar':
    delete:
      summary: Delete instance avatar
      security:
        - OAuth2:
          - admin
      tags:
        - Config
      responses:
        '204':
          description: successful operation

  '/api/v1/config/instance-logo/{logoType}/pick':
    post:
      summary: Update instance logo
      security:
        - OAuth2:
          - admin
      tags:
        - Config
      parameters:
        - $ref: '#/components/parameters/logoTypeParam'
      responses:
        '204':
          description: successful operation
        '413':
          description: image file too large
          headers:
            X-File-Maximum-Size:
              schema:
                type: string
                format: Nginx size
              description: Maximum file size for the banner
      requestBody:
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                logofile:
                  description: The file to upload.
                  type: string
                  format: binary
            encoding:
              logofile:
                contentType: image/png, image/jpeg

  '/api/v1/config/instance-logo/{logoType}':
    delete:
      summary: Delete instance logo
      security:
        - OAuth2:
          - admin
      tags:
        - Config
      parameters:
        - $ref: '#/components/parameters/logoTypeParam'
      responses:
        '204':
          description: successful operation

  /api/v1/custom-pages/homepage/instance:
    get:
      summary: Get instance custom homepage
      tags:
        - Homepage
      responses:
        '404':
          description: No homepage set
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CustomHomepage'
    put:
      summary: Set instance custom homepage
      tags:
        - Homepage
      security:
        - OAuth2:
          - admin
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                content:
                  type: string
                  description: content of the homepage, that will be injected in the client
      responses:
        '204':
          description: successful operation

  /api/v1/jobs/pause:
    post:
      summary: Pause job queue
      security:
        - OAuth2:
          - admin
      tags:
        - Job
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                processRoles:
                  type: array
                  minItems: 1
                  items:
                    type: string
                    enum:
                      - primary
                      - secondary
                  description: >-
                    Roles of the PeerTube processes that must pause their job queue.
                    Defaults to all the roles.
                    Other processes are notified asynchronously.
      responses:
        '204':
          description: successful operation

  /api/v1/jobs/resume:
    post:
      summary: Resume job queue
      security:
        - OAuth2:
          - admin
      tags:
        - Job
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                processRoles:
                  type: array
                  minItems: 1
                  items:
                    type: string
                    enum:
                      - primary
                      - secondary
                  description: >-
                    Roles of the PeerTube processes that must resume their job queue.
                    Defaults to all the roles.
                    Other processes are notified asynchronously.
      responses:
        '204':
          description: successful operation

  /api/v1/jobs/{state}:
    get:
      summary: List instance jobs
      operationId: getJobs
      security:
        - OAuth2:
          - admin
      tags:
        - Job
      parameters:
        - name: state
          in: path
          required: true
          description: The state of the job ('' for for no filter)
          schema:
            type: string
            enum:
              - ''
              - active
              - completed
              - failed
              - waiting
              - delayed
        - $ref: '#/components/parameters/jobType'
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/sort'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  total:
                    type: integer
                    example: 1
                  data:
                    type: array
                    maxItems: 100
                    items:
                      $ref: '#/components/schemas/Job'

  /api/v1/jobs/{jobType}/{jobId}/cancel:
    post:
      summary: Cancel a job
      description: Abort a running job and its underlying ffmpeg/child process. Only active jobs that support cancellation can be cancelled.
      operationId: cancelJob
      security:
        - OAuth2:
          - admin
      tags:
        - Job
      parameters:
        - name: jobType
          in: path
          required: true
          description: The type of the job to cancel
          schema:
            $ref: '#/components/schemas/JobType'
        - name: jobId
          in: path
          required: true
          description: The id of the job to cancel
          schema:
            type: string
      responses:
        '204':
          description: successful operation
        '404':
          description: job not found
        '409':
          description: job cannot be cancelled (not active or not cancellable)

  /api/v1/server/followers:
    get:
      tags:
        - Instance Follows
      summary: List instances following the server
      parameters:
        - $ref: '#/components/parameters/followState'
        - $ref: '#/components/parameters/actorType'
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/sort'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  total:
                    type: integer
                    example: 1
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Follow'

  '/api/v1/server/followers/{handle}':
    delete:
      summary: Remove or reject a follower to your server
      security:
        - OAuth2:
          - admin
      tags:
        - Instance Follows
      parameters:
        - name: handle
          in: path
          required: true
          description: The remote actor handle to remove from your followers
          schema:
            type: string
            format: email
      responses:
        '204':
          description: successful operation
        '404':
          description: follower not found

  '/api/v1/server/followers/{handle}/reject':
    post:
      summary: Reject a pending follower to your server
      security:
        - OAuth2:
          - admin
      tags:
        - Instance Follows
      parameters:
        - name: handle
          in: path
          required: true
          description: The remote actor handle to remove from your followers
          schema:
            type: string
            format: email
      responses:
        '204':
          description: successful operation
        '404':
          description: follower not found

  '/api/v1/server/followers/{handle}/accept':
    post:
      summary: Accept a pending follower to your server
      security:
        - OAuth2:
          - admin
      tags:
        - Instance Follows
      parameters:
        - name: handle
          in: path
          required: true
          description: The remote actor handle to remove from your followers
          schema:
            type: string
            format: email
      responses:
        '204':
          description: successful operation
        '404':
          description: follower not found

  /api/v1/server/following:
    get:
      tags:
        - Instance Follows
      summary: List instances followed by the server
      parameters:
        - $ref: '#/components/parameters/followState'
        - $ref: '#/components/parameters/actorType'
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/sort'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  total:
                    type: integer
                    example: 1
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Follow'
    post:
      security:
        - OAuth2:
          - admin
      tags:
        - Instance Follows
      summary: Follow a list of actors (PeerTube instance, channel or account)
      responses:
        '204':
          description: successful operation
        '500':
          description: cannot follow a non-HTTPS server
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                hosts:
                  type: array
                  items:
                    type: string
                    format: hostname
                  uniqueItems: true
                handles:
                  type: array
                  items:
                    type: string
                  uniqueItems: true

  '/api/v1/server/following/{hostOrHandle}':
    delete:
      summary: Unfollow an actor (PeerTube instance, channel or account)
      security:
        - OAuth2:
          - admin
      tags:
        - Instance Follows
      parameters:
        - name: hostOrHandle
          in: path
          required: true
          description: The hostOrHandle to unfollow
          schema:
            type: string
      responses:
        '204':
          description: successful operation
        '404':
          description: host or handle not found

  /api/v1/users:
    post:
      summary: Create a user
      operationId: addUser
      security:
        - OAuth2:
          - admin
      tags:
        - Users
      responses:
        '200':
          description: user created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AddUserResponse'
          links:
            # GET /users/{id}
            GetUser:
              operationId: getUser
              parameters:
                id: '$response.body#/user/id'
            # PUT /users/{id}
            PutUser:
              operationId: putUser
              parameters:
                id: '$response.body#/user/id'
            # DELETE /users/{id}
            DelUser:
              operationId: delUser
              parameters:
                id: '$response.body#/user/id'
        '403':
          description: insufficient authority to create an admin or moderator
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AddUser'
        description: |
          If the smtp server is configured, you can leave the password empty and an email will be sent
          asking the user to set it first.
        required: true
    get:
      summary: List users
      operationId: getUsers
      security:
        - OAuth2:
          - admin
      tags:
        - Users
      parameters:
        - $ref: '#/components/parameters/usersSearch'
        - $ref: '#/components/parameters/usersBlocked'
        - $ref: '#/components/parameters/usersRole'
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/usersSort'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/User'

  '/api/v1/users/{id}':
    parameters:
      - $ref: '#/components/parameters/id'
    delete:
      summary: Delete a user
      security:
        - OAuth2:
          - admin
      tags:
        - Users
      operationId: delUser
      responses:
        '204':
          description: successful operation
    get:
      summary: Get a user
      security:
        - OAuth2: []
      tags:
        - Users
      operationId: getUser
      parameters:
        - name: withStats
          in: query
          description: include statistics about the user (only available as a moderator/admin)
          schema:
            type: boolean
      responses:
        '200':
          x-summary: successful operation
          description: |
            As an admin/moderator, you can request a response augmented with statistics about the user's
            moderation relations and videos usage, by using the `withStats` parameter.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/User'
                  - $ref: '#/components/schemas/UserWithStats'
    put:
      summary: Update a user
      security:
        - OAuth2: []
      tags:
        - Users
      operationId: putUser
      responses:
        '204':
          description: successful operation
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateUser'
        required: true

  /api/v1/users/{id}/block:
    post:
      summary: Block a user
      description: Prevent a user from logging in and interacting with the instance
      security:
        - OAuth2:
          - admin
      tags:
        - Users
      parameters:
        - $ref: '#/components/parameters/id'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                reason:
                  type: string
                  description: Optional reason for blocking the user
                  minLength: 0
                  maxLength: 500
      responses:
        '204':
          description: successful operation
        '400':
          description: invalid user id
        '403':
          description: insufficient permissions to block users
        '404':
          description: user not found

  /api/v1/users/{id}/unblock:
    post:
      summary: Unblock a user
      description: Allow a previously blocked user to login and interact with the instance
      security:
        - OAuth2:
          - admin
      tags:
        - Users
      parameters:
        - $ref: '#/components/parameters/id'
      responses:
        '204':
          description: successful operation
        '400':
          description: invalid user id
        '403':
          description: insufficient permissions to unblock users
        '404':
          description: user not found

  /api/v1/oauth-clients/local:
    get:
      summary: Login prerequisite
      description: You need to retrieve a client id and secret before [logging in](#operation/getOAuthToken).
      operationId: getOAuthClient
      tags:
        - Session
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OAuthClient'
          links:
            UseOAuthClientToLogin:
              operationId: getOAuthToken
              parameters:
                client_id: '$response.body#/client_id'
                client_secret: '$response.body#/client_secret'
      x-codeSamples:
        - lang: Shell
          source: |
            API="https://peertube2.cpy.re/api/v1"

            ## AUTH
            curl -s "$API/oauth-clients/local"

  /api/v1/users/token:
    post:
      summary: Login
      operationId: getOAuthToken
      description: With your [client id and secret](#operation/getOAuthClient), you can retrieve an access and refresh tokens.
      tags:
        - Session
      parameters:
        - name: x-peertube-otp
          in: header
          schema:
            type: string
          required: false
          description: If the user enabled two factor authentication, you need to provide the OTP code in this header
      requestBody:
        content:
          application/x-www-form-urlencoded:
            schema:
              oneOf:
                - $ref: '#/components/schemas/OAuthToken-password'
                - $ref: '#/components/schemas/OAuthToken-refresh_token'
              discriminator:
                propertyName: grant_type
                mapping:
                  password: '#/components/schemas/OAuthToken-password'
                  refresh_token: '#/components/schemas/OAuthToken-refresh_token'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  token_type:
                    type: string
                    example: Bearer
                  access_token:
                    type: string
                    example: 90286a0bdf0f7315d9d3fe8dabf9e1d2be9c97d0
                    description: valid for 1 day
                  refresh_token:
                    type: string
                    example: 2e0d675df9fc96d2e4ec8a3ebbbf45eca9137bb7
                    description: valid for 2 weeks
                  expires_in:
                    type: integer
                    minimum: 0
                    example: 14399
                  refresh_token_expires_in:
                    type: integer
                    minimum: 0
                    example: 1209600
        '400':
          x-summary: client or credentials are invalid
          description: |
            Disambiguate via `code`:
            - `invalid_client` for an unmatched `client_id`
            - `invalid_grant` for unmatched credentials
        '401':
          x-summary: token expired or two factor header is missing
          description: |
            Disambiguate via `code`:
            - default value for a regular authentication failure
            - `invalid_token` for an expired token
            - `missing_two_factor` if two factor header is missing
      x-codeSamples:
        - lang: Shell
          source: |
            ## DEPENDENCIES: jq
            API="https://peertube2.cpy.re/api/v1"
            USERNAME="<your_username>"
            PASSWORD="<your_password>"

            ## AUTH
            client_id=$(curl -s "$API/oauth-clients/local" | jq -r ".client_id")
            client_secret=$(curl -s "$API/oauth-clients/local" | jq -r ".client_secret")
            curl -s "$API/users/token" \
              --data client_id="$client_id" \
              --data client_secret="$client_secret" \
              --data grant_type=password \
              --data username="$USERNAME" \
              --data-urlencode password="$PASSWORD" \
              | jq -r ".access_token"

  /api/v1/users/revoke-token:
    post:
      summary: Logout
      description: Revokes your access token and its associated refresh token, destroying your current session.
      operationId: revokeOAuthToken
      tags:
        - Session
      security:
        - OAuth2: []
      responses:
        '200':
          description: successful operation

  /api/v1/users/{id}/token-sessions:
    get:
      summary: List token sessions
      parameters:
        - $ref: '#/components/parameters/id'
      tags:
        - Session
      security:
        - OAuth2: []
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  total:
                    type: integer
                    example: 1
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/TokenSession'

  /api/v1/users/{id}/token-sessions/{tokenSessionId}/revoke:
    get:
      summary: List token sessions
      parameters:
        - $ref: '#/components/parameters/id'
        - $ref: '#/components/parameters/tokenSessionId'
      tags:
        - Session
      security:
        - OAuth2: []
      responses:
        '200':
          description: successful operation

  /api/v1/users/ask-send-verify-email:
    post:
      summary: Resend user verification link
      operationId: resendEmailToVerifyUser
      tags:
        - Users
        - Register
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                email:
                  type: string
                  description: User email
              required:
                - email
      responses:
        '204':
          description: successful operation

  /api/v1/users/registrations/ask-send-verify-email:
    post:
      summary: Resend verification link to registration request email
      operationId: resendEmailToVerifyRegistration
      tags:
        - Register
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                email:
                  type: string
                  description: Registration email
              required:
                - email
      responses:
        '204':
          description: successful operation

  /api/v1/users/{id}/verify-email:
    post:
      summary: Verify a user
      operationId: verifyUser
      description: |
        Following a user registration, the new user will receive an email asking to click a link
        containing a secret.
        This endpoint can also be used to verify a new email set in the user account.
      tags:
        - Users
        - Register
      parameters:
        - $ref: '#/components/parameters/id'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                verificationString:
                  type: string
                  format: url
                isPendingEmail:
                  type: boolean
              required:
                - verificationString
      responses:
        '204':
          description: successful operation
        '403':
          description: invalid verification string
        '404':
          description: user not found

  /api/v1/users/registrations/{registrationId}/verify-email:
    post:
      summary: Verify a registration email
      operationId: verifyRegistrationEmail
      description: |
        Following a user registration request, the user will receive an email asking to click a link
        containing a secret.
      tags:
        - Register
      parameters:
        - $ref: '#/components/parameters/registrationId'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                verificationString:
                  type: string
                  format: url
              required:
                - verificationString
      responses:
        '204':
          description: successful operation
        '403':
          description: invalid verification string
        '404':
          description: registration not found

  /api/v1/users/ask-reset-password:
    post:
      summary: Ask to reset password
      description: An email containing a reset password link
      tags:
        - Users
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                email:
                  type: string
                  description: User email
              required:
                - email
      responses:
        '204':
          description: successful operation

  /api/v1/users/{id}/reset-password:
    post:
      summary: Reset password
      tags:
        - Users
      parameters:
        - $ref: '#/components/parameters/id'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                verificationString:
                  type: string
                  format: url
                password:
                  type: string
              required:
                - verificationString
                - password
      responses:
        '204':
          description: successful operation
        '403':
          description: invalid verification string
        '404':
          description: user not found

  /api/v1/users/{id}/two-factor/request:
    post:
      summary: Request two factor auth
      operationId: requestTwoFactor
      description: Request two factor authentication for a user
      security:
        - OAuth2: []
      tags:
        - Users
      parameters:
        - $ref: '#/components/parameters/id'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                currentPassword:
                  type: string
                  description: Password of the currently authenticated user
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/RequestTwoFactorResponse'
        '403':
          description: invalid password
        '404':
          description: user not found
        '429':
          description: too many password checks for this user

  /api/v1/users/{id}/two-factor/confirm-request:
    post:
      summary: Confirm two factor auth
      operationId: confirmTwoFactorRequest
      description: Confirm a two factor authentication request
      security:
        - OAuth2: []
      tags:
        - Users
      parameters:
        - $ref: '#/components/parameters/id'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                requestToken:
                  type: string
                  description: Token to identify the two factor request
                otpToken:
                  type: string
                  description: OTP token generated by the app
              required:
                - requestToken
                - otpToken
      responses:
        '204':
          description: successful operation
        '403':
          description: invalid request token or OTP token
        '404':
          description: user not found

  /api/v1/users/{id}/two-factor/disable:
    post:
      summary: Disable two factor auth
      operationId: disableTwoFactor
      description: Disable two factor authentication of a user
      security:
        - OAuth2: []
      tags:
        - Users
      parameters:
        - $ref: '#/components/parameters/id'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                currentPassword:
                  type: string
                  description: Password of the currently authenticated user. Users of an id and pass auth plugin must use the password they log in with
      responses:
        '204':
          description: successful operation
        '403':
          description: invalid password
        '404':
          description: user not found
        '429':
          description: too many password checks for this user

  /api/v1/users/{userId}/imports/import-resumable:
    post:
      summary: Initialize the resumable user import
      description: "**PeerTube >= 6.1** Uses [a resumable protocol](https://github.com/kukhariev/node-uploadx/blob/master/proto.md) to initialize the import of the archive"
      operationId: userImportResumableInit
      security:
        - OAuth2: []
      tags:
        - User Imports
      parameters:
        - $ref: '#/components/parameters/userId'
        - $ref: '#/components/parameters/resumableUploadInitContentLengthHeader'
        - $ref: '#/components/parameters/resumableUploadInitContentTypeHeader'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UserImportResumable'
      responses:
        '201':
          description: created
          headers:
            Location:
              schema:
                type: string
                format: url
            Content-Length:
              schema:
                type: number
                example: 0
    put:
      summary: Send chunk for the resumable user import
      description: "**PeerTube >= 6.1** Uses [a resumable protocol](https://github.com/kukhariev/node-uploadx/blob/master/proto.md) to continue, pause or resume the import of the archive"
      operationId: userImportResumable
      security:
        - OAuth2: []
      tags:
        - User Imports
      parameters:
        - $ref: '#/components/parameters/userId'
        - $ref: '#/components/parameters/resumableUploadId'
        - $ref: '#/components/parameters/resumableUploadChunkContentRangeHeader'
        - $ref: '#/components/parameters/resumableUploadChunkContentLengthHeader'
      requestBody:
        content:
          application/octet-stream:
            schema:
              type: string
              format: binary
      responses:
        '204':
          description: 'last chunk received: successful operation'
        '308':
          description: resume incomplete
          headers:
            Range:
              schema:
                type: string
                example: bytes=0-262143
            Content-Length:
              schema:
                type: number
                example: 0
        '400':
          description: chunk is smaller than `import.users.resumableUpload.minChunkSize` of the server config or 1/10,000 of the file size (and is not the last one)
        '503':
          description: upload is already being processed
          headers:
            'Retry-After':
              schema:
                type: number
                example: 300
    delete:
      summary: Cancel the resumable user import
      description: "**PeerTube >= 6.1** Uses [a resumable protocol](https://github.com/kukhariev/node-uploadx/blob/master/proto.md) to cancel the resumable user import"
      operationId: userImportResumableCancel
      security:
        - OAuth2: []
      tags:
        - User Imports
      parameters:
        - $ref: '#/components/parameters/userId'
        - $ref: '#/components/parameters/resumableUploadId'
        - name: Content-Length
          in: header
          required: true
          schema:
            type: number
            example: 0
      responses:
        '204':
          description: import cancelled
          headers:
            Content-Length:
              schema:
                type: number
                example: 0

  /api/v1/users/{userId}/imports/latest:
    get:
      summary: Get latest user import
      description: "**PeerTube >= 6.1**"
      operationId: getLatestUserImport
      security:
        - OAuth2: []
      tags:
        - User Imports
      parameters:
        - $ref: '#/components/parameters/userId'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: integer
                  state:
                    type: object
                    properties:
                      id:
                        $ref: '#/components/schemas/UserImportState'
                      label:
                        type: string
                  createdAt:
                    type: string
                    format: date-time

  /api/v1/users/{userId}/exports/request:
    post:
      summary: Request user export
      operationId: requestUserExport
      description: Request an archive of user data. An email is sent when the archive is ready.
      security:
        - OAuth2: []
      tags:
        - User Exports
      parameters:
        - $ref: '#/components/parameters/userId'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                withVideoFiles:
                  type: boolean
                  description: Whether to include video files in the archive
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  export:
                    type: object
                    properties:
                      id:
                        type: integer

  /api/v1/users/{userId}/exports:
    get:
      summary: List user exports
      description: "**PeerTube >= 6.1**"
      operationId: listUserExports
      security:
        - OAuth2: []
      tags:
        - User Exports
      parameters:
        - $ref: '#/components/parameters/userId'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: integer
                  state:
                    type: object
                    properties:
                      id:
                        $ref: '#/components/schemas/UserExportState'
                      label:
                        type: string
                  size:
                    type: integer
                    description: Size of the archive file in bytes
                  privateDownloadUrl:
                    type: string
                    description: This URL already contains the JWT token, so no additional authentication credentials are required
                  createdAt:
                    type: string
                    format: date-time
                  expiresOn:
                    type: string
                    format: date-time
  /api/v1/users/{userId}/exports/{id}:
    delete:
      summary: Delete a user export
      description: "**PeerTube >= 6.1**"
      operationId: deleteUserExport
      security:
        - OAuth2: []
      tags:
        - User Exports
      parameters:
        - $ref: '#/components/parameters/userId'
        - $ref: '#/components/parameters/id'
      responses:
        '204':
          description: successful operation

  /api/v1/users/me:
    get:
      summary: Get my user information
      operationId: getUserInfo
      security:
        - OAuth2:
          - user
      tags:
        - My User
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/User'
    put:
      summary: Update my user information
      operationId: putUserInfo
      security:
        - OAuth2:
          - user
      tags:
        - My User
      responses:
        '204':
          description: successful operation
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateMe'
        required: true
    delete:
      summary: Delete my account
      operationId: deleteMe
      description: Delete the authenticated user's account and all associated data
      security:
        - OAuth2:
          - user
      tags:
        - My User
      responses:
        '204':
          description: successful operation - account deleted
        '400':
          description: invalid request parameters
        '401':
          description: authentication required

  '/api/v1/users/me/videos/comments':
    get:
      summary: List comments on user's videos
      description: "**PeerTube >= 6.2**"
      security:
        - OAuth2: []
      tags:
        - Video Comments
      parameters:
        - $ref: '#/components/parameters/search'
        - $ref: '#/components/parameters/searchAccountForComments'
        - $ref: '#/components/parameters/searchVideoForComments'
        - $ref: '#/components/parameters/videoId'
        - $ref: '#/components/parameters/videoChannelId'
        - $ref: '#/components/parameters/autoTagOneOfComment'
        - $ref: '#/components/parameters/isHeldForReview'
        - $ref: '#/components/parameters/includeCollaborations'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  total:
                    type: integer
                    example: 1
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/VideoCommentForOwnerOrAdmin'

  /api/v1/users/me/videos/imports:
    get:
      summary: Get video imports of my user
      security:
        - OAuth2:
          - user
      tags:
        - Videos
        - My User
      parameters:
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/sort'
        - $ref: '#/components/parameters/includeCollaborations'
        -
          name: videoId
          in: query
          required: false
          description: Filter on import video ID
          schema:
            type: integer
        -
          name: targetUrl
          in: query
          required: false
          description: Filter on import target URL
          schema:
            type: string
        -
          name: videoChannelSyncId
          in: query
          required: false
          description: Filter on imports created by a specific channel synchronization
          schema:
            type: number
        -
          name: search
          in: query
          required: false
          description: Search in video names
          schema:
            type: string
        -
          name: stateOneOf
          in: query
          required: false
          description: Filter on import state
          schema:
            type: array
            items:
              $ref: '#/components/schemas/VideoImportStateConstant/properties/id'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VideoImportsList'

  /api/v1/users/me/video-quota-used:
    get:
      summary: Get my user used quota
      security:
        - OAuth2:
          - user
      tags:
        - My User
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  videoQuotaUsed:
                    type: number
                    description: The user video quota used so far in bytes
                    example: 16810141515
                  videoQuotaUsedDaily:
                    type: number
                    description: The user video quota used today in bytes
                    example: 1681014151

  '/api/v1/users/me/videos/{videoIdOrUUID}/rating':
    get:
      summary: Get rate of my user for a video
      security:
        - OAuth2: []
      tags:
        - My User
        - Video Rates
      parameters:
        - $ref: '#/components/parameters/videoIdOrUUID'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GetMeVideoRating'

  /api/v1/users/me/videos:
    get:
      summary: List videos of my user
      security:
        - OAuth2:
          - user
      tags:
        - My User
        - Videos
      parameters:
        - $ref: '#/components/parameters/channelNameOneOf'
        # Common video filter parameters
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/skipCount'
        - $ref: '#/components/parameters/videosSort'
        - $ref: '#/components/parameters/nsfw'
        - $ref: '#/components/parameters/nsfwFlagsIncluded'
        - $ref: '#/components/parameters/nsfwFlagsExcluded'
        - $ref: '#/components/parameters/aiUsageOneOf'
        - $ref: '#/components/parameters/isLive'
        - $ref: '#/components/parameters/includeScheduledLive'
        - $ref: '#/components/parameters/categoryOneOf'
        - $ref: '#/components/parameters/licenceOneOf'
        - $ref: '#/components/parameters/languageOneOf'
        - $ref: '#/components/parameters/tagsOneOf'
        - $ref: '#/components/parameters/tagsAllOf'
        - $ref: '#/components/parameters/isLocal'
        - $ref: '#/components/parameters/include'
        - $ref: '#/components/parameters/hasHLSFiles'
        - $ref: '#/components/parameters/hasWebVideoFiles'
        - $ref: '#/components/parameters/host'
        - $ref: '#/components/parameters/autoTagOneOfVideo'
        - $ref: '#/components/parameters/stateOneOfVideo'
        - $ref: '#/components/parameters/privacyOneOf'
        - $ref: '#/components/parameters/excludeAlreadyWatched'
        - $ref: '#/components/parameters/search'
        - $ref: '#/components/parameters/includeCollaborations'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VideoListResponse'

  /api/v1/users/me/subscriptions:
    get:
      summary: List my user subscriptions
      security:
        - OAuth2:
          - user
      tags:
        - My Subscriptions
      parameters:
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/mySubscriptionSort'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VideoChannelList'
    post:
      tags:
        - My Subscriptions
      summary: Add subscription to my user
      security:
        - OAuth2:
          - user
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                uri:
                  type: string
                  format: uri
                  description: uri of the video channels to subscribe to
              required:
                - uri
            examples:
              default:
                value:
                  uri: 008a0e54-375d-49d0-8379-143202e24152@video.lqdn.fr
      responses:
        '204':
          description: successful operation

  /api/v1/users/me/subscriptions/exist:
    get:
      summary: Get if subscriptions exist for my user
      security:
        - OAuth2:
          - user
      tags:
        - My Subscriptions
      parameters:
        - $ref: '#/components/parameters/subscriptionsUris'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object

  /api/v1/users/me/subscriptions/videos:
    get:
      summary: List videos of subscriptions of my user
      security:
        - OAuth2:
          - user
      tags:
        - My Subscriptions
        - Videos
      parameters:
        # Common video filter parameters
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/skipCount'
        - $ref: '#/components/parameters/videosSort'
        - $ref: '#/components/parameters/nsfw'
        - $ref: '#/components/parameters/nsfwFlagsIncluded'
        - $ref: '#/components/parameters/nsfwFlagsExcluded'
        - $ref: '#/components/parameters/aiUsageOneOf'
        - $ref: '#/components/parameters/isLive'
        - $ref: '#/components/parameters/includeScheduledLive'
        - $ref: '#/components/parameters/categoryOneOf'
        - $ref: '#/components/parameters/licenceOneOf'
        - $ref: '#/components/parameters/languageOneOf'
        - $ref: '#/components/parameters/tagsOneOf'
        - $ref: '#/components/parameters/tagsAllOf'
        - $ref: '#/components/parameters/isLocal'
        - $ref: '#/components/parameters/include'
        - $ref: '#/components/parameters/hasHLSFiles'
        - $ref: '#/components/parameters/hasWebVideoFiles'
        - $ref: '#/components/parameters/host'
        - $ref: '#/components/parameters/autoTagOneOfVideo'
        - $ref: '#/components/parameters/stateOneOfVideo'
        - $ref: '#/components/parameters/privacyOneOf'
        - $ref: '#/components/parameters/excludeAlreadyWatched'
        - $ref: '#/components/parameters/search'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VideoListResponse'

  '/api/v1/users/me/subscriptions/{subscriptionHandle}':
    get:
      summary: Get subscription of my user
      security:
        - OAuth2:
          - user
      tags:
        - My Subscriptions
      parameters:
        - $ref: '#/components/parameters/subscriptionHandle'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VideoChannel'
    delete:
      summary: Delete subscription of my user
      security:
        - OAuth2:
          - user
      tags:
        - My Subscriptions
      parameters:
        - $ref: '#/components/parameters/subscriptionHandle'
      responses:
        '204':
          description: successful operation

  /api/v1/users/me/notifications:
    get:
      summary: List my notifications
      security:
        - OAuth2: []
      tags:
        - My Notifications
      parameters:
        - name: typeOneOf
          in: query
          description: only list notifications of these types
          schema:
            type: array
            items:
              $ref: '#/components/schemas/NotificationType'
        - name: unread
          in: query
          description: only list unread notifications
          schema:
            type: boolean
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/sort'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotificationListResponse'

  /api/v1/users/me/notifications/read:
    post:
      summary: Mark notifications as read by their id
      security:
        - OAuth2: []
      tags:
        - My Notifications
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                ids:
                  type: array
                  description: ids of the notifications to mark as read
                  items:
                    type: integer
              required:
                - ids
      responses:
        '204':
          description: successful operation

  /api/v1/users/me/notifications/read-all:
    post:
      summary: Mark all my notification as read
      security:
        - OAuth2: []
      tags:
        - My Notifications
      responses:
        '204':
          description: successful operation

  /api/v1/users/me/notification-settings:
    put:
      summary: Update my notification settings
      security:
        - OAuth2: []
      tags:
        - My Notifications
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UserNotificationSettings'

      responses:
        '204':
          description: successful operation

  /api/v1/users/me/new-feature-info/read:
    post:
      tags:
        - My User
      summary: Mark feature info as read
      description: "**PeerTube >= v8.0.0"
      security:
        - OAuth2:
          - user
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                feature:
                  $ref: '#/components/schemas/NewFeatureInfoType'
              required:
                - feature
      responses:
        '204':
          description: successful operation

  /api/v1/users/me/history/videos:
    get:
      summary: List watched videos history
      security:
        - OAuth2: []
      tags:
        - My History
      parameters:
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/search'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VideoListResponse'

  /api/v1/users/me/history/videos/{videoIdOrUUID}:
    delete:
      summary: Delete history element
      security:
        - OAuth2: []
      tags:
        - My History
      parameters:
        - $ref: '#/components/parameters/videoIdOrUUID'
      responses:
        '204':
          description: successful operation

  /api/v1/users/me/history/videos/remove:
    post:
      summary: Clear video history
      security:
        - OAuth2: []
      tags:
        - My History
      requestBody:
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                beforeDate:
                  description: history before this date will be deleted
                  type: string
                  format: date-time
      responses:
        '204':
          description: successful operation

  /api/v1/users/me/avatar/pick:
    post:
      summary: Update my user avatar
      security:
        - OAuth2: []
      tags:
        - My User
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  avatars:
                    type: array
                    items:
                      $ref: '#/components/schemas/ActorImage'
        '413':
          description: image file too large
          headers:
            X-File-Maximum-Size:
              schema:
                type: string
                format: Nginx size
              description: Maximum file size for the avatar
      requestBody:
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                avatarfile:
                  description: The file to upload
                  type: string
                  format: binary
            encoding:
              avatarfile:
                contentType: image/png, image/jpeg

  /api/v1/users/me/avatar:
    delete:
      summary: Delete my avatar
      security:
        - OAuth2: []
      tags:
        - My User
      responses:
        '204':
          description: successful operation

  /api/v1/users/register:
    post:
      summary: Register a user
      operationId: registerUser
      description: Signup has to be enabled and signup approval is not required
      tags:
        - Register
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  state:
                    type: object
                    properties:
                      id:
                        $ref: '#/components/schemas/UserRegistrationState'
                      label:
                        type: string
        '400':
          description: request error
        '403':
          description: user registration is not enabled, user limit is reached, registration is not allowed for the ip, requires approval or blocked by a plugin
        '409':
          description: 'a user with this username, channel name or email already exists'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RegisterUser'
        required: true

  /api/v1/users/registrations/request:
    post:
      summary: Request registration
      description: Signup has to be enabled and require approval on the instance
      operationId: requestRegistration
      tags:
        - Register
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  state:
                    type: object
                    properties:
                      id:
                        $ref: '#/components/schemas/UserRegistrationState'
                      label:
                        type: string
        '400':
          description: request error or signup approval is not enabled on the instance
        '403':
          description: user registration is not enabled, user limit is reached, registration is not allowed for the ip or blocked by a plugin
        '409':
          description: 'a user or registration with this username, channel name or email already exists'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UserRegistrationRequest'

  /api/v1/users/registrations/{registrationId}/accept:
    post:
      security:
        - OAuth2:
          - admin
          - moderator
      summary: Accept registration
      operationId: acceptRegistration
      tags:
        - Register
      parameters:
        - $ref: '#/components/parameters/registrationId'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UserRegistrationAcceptOrReject'
      responses:
        '204':
          description: successful operation

  /api/v1/users/registrations/{registrationId}/reject:
    post:
      security:
        - OAuth2:
          - admin
          - moderator
      summary: Reject registration
      operationId: rejectRegistration
      tags:
        - Register
      parameters:
        - $ref: '#/components/parameters/registrationId'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UserRegistrationAcceptOrReject'
      responses:
        '204':
          description: successful operation

  /api/v1/users/registrations/{registrationId}:
    delete:
      security:
        - OAuth2:
          - admin
          - moderator
      summary: Delete registration
      description: 'Delete the registration entry. It will not remove the user associated with this registration (if any)'
      operationId: deleteRegistration
      tags:
        - Register
      parameters:
        - $ref: '#/components/parameters/registrationId'
      responses:
        '204':
          description: successful operation

  /api/v1/users/registrations:
    get:
      security:
        - OAuth2:
          - admin
          - moderator
      summary: List registrations
      operationId: listRegistrations
      tags:
        - Register
      parameters:
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - name: search
          in: query
          required: false
          schema:
            type: string
        - name: sort
          in: query
          required: false
          schema:
            type: string
            enum:
            - -createdAt
            - createdAt
            - state
            - -state
        - name: stateOneOf
          in: query
          required: false
          schema:
            type: array
            items:
              $ref: '#/components/schemas/UserRegistrationState'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  total:
                    type: integer
                    example: 1
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/UserRegistration'

  /api/v1/videos/ownership:
    get:
      summary: List video ownership changes
      description: List ownership change requests received by the authenticated user and requests sent by a channel managed by the authenticated user
      tags:
        - Ownership Change
      security:
        - OAuth2: []
      parameters:
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - name: sort
          in: query
          required: false
          schema:
            type: string
            enum:
              - -createdAt
              - createdAt
      responses:
        '200':
          description: successful operation
          content:
            'application/json':
              schema:
                type: object
                properties:
                  total:
                    type: integer
                    example: 1
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/ChangeOwnership'
        '401':
          description: authentication required

  '/api/v1/videos/ownership/{id}/accept':
    post:
      summary: Accept ownership change request
      tags:
        - Ownership Change
      security:
        - OAuth2: []
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                channelId:
                  type: integer
                  description: Target channel id owned by the authenticated user
              required:
                - channelId
      responses:
        '204':
          description: successful operation
        '400':
          description: ownership change request already accepted/refused or invalid target channel id
        '403':
          description: cannot terminate an ownership change of another user
        '413':
          description: quota exceeded for the target account/channel
        '404':
          description: video ownership change not found

  '/api/v1/videos/ownership/{id}/refuse':
    post:
      summary: Refuse ownership change request
      tags:
        - Ownership Change
      security:
        - OAuth2: []
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
      responses:
        '204':
          description: successful operation
        '400':
          description: ownership change request already accepted/refused
        '403':
          description: cannot terminate an ownership change of another user
        '404':
          description: video ownership change not found

  '/api/v1/videos/ownership/{id}':
    delete:
      summary: Delete ownership change request
      description: Delete an ownership change request. Only users who can manage the video can delete the request.
      tags:
        - Ownership Change
      security:
        - OAuth2: []
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
      responses:
        '204':
          description: successful operation
        '400':
          description: ownership request already accepted or refused
        '403':
          description: only users who can manage the video can delete an ownership change request
        '404':
          description: video ownership change not found

  '/api/v1/videos/{videoIdOrUUID}/ownership':
    get:
      summary: List ownership change requests for a video
      description: List all ownership change requests for a specific video. The authenticated user must be able to manage the video.
      tags:
        - Ownership Change
      security:
        - OAuth2: []
      parameters:
        - $ref: '#/components/parameters/videoIdOrUUID'
        - name: state
          in: query
          required: false
          description: Filter by ownership change state
          schema:
            $ref: '#/components/schemas/ChangeOwnershipState'
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - name: sort
          in: query
          required: false
          schema:
            type: string
            enum:
              - -createdAt
              - createdAt
      responses:
        '200':
          description: successful operation
          content:
            'application/json':
              schema:
                type: object
                properties:
                  total:
                    type: integer
                    example: 1
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/ChangeOwnership'
        '403':
          description: cannot manage the video
        '404':
          description: video not found

  '/api/v1/videos/{videoIdOrUUID}/give-ownership':
    post:
      summary: Request ownership change
      tags:
        - Ownership Change
      security:
        - OAuth2: []
      parameters:
        - $ref: '#/components/parameters/videoIdOrUUID'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                username:
                  type: string
              required:
                - username
      responses:
        '204':
          description: successful operation
        '400':
          description: changing video ownership to a remote account is not supported yet or there is already a pending ownership request
        '403':
          description: cannot change ownership of this video
        '404':
          description: video not found

  /api/v1/video-channels/ownership:
    get:
      summary: List channel ownership changes
      description: List ownership change requests received by the authenticated user and requests sent by channels managed by the authenticated user
      tags:
        - Ownership Change
      security:
        - OAuth2: []
      parameters:
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - name: sort
          in: query
          required: false
          schema:
            type: string
            enum:
              - -createdAt
              - createdAt
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  total:
                    type: integer
                    example: 1
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/ChangeOwnership'
        '401':
          description: authentication required

  '/api/v1/video-channels/ownership/{id}/accept':
    post:
      summary: Accept channel ownership change request
      tags:
        - Ownership Change
      security:
        - OAuth2: []
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
      responses:
        '204':
          description: successful operation
        '400':
          description: ownership change request already accepted/refused or request type mismatch
        '403':
          description: cannot terminate an ownership change of another user
        '404':
          description: channel ownership change not found
        '409':
          description: cannot accept transferring the last channel of the initiator account
        '413':
          description: quota exceeded for the target account

  '/api/v1/video-channels/ownership/{id}/refuse':
    post:
      summary: Refuse channel ownership change request
      tags:
        - Ownership Change
      security:
        - OAuth2: []
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
      responses:
        '204':
          description: successful operation
        '400':
          description: ownership change request already accepted/refused or request type mismatch
        '403':
          description: cannot terminate an ownership change of another user
        '404':
          description: channel ownership change not found

  '/api/v1/video-channels/ownership/{id}':
    delete:
      summary: Delete channel ownership change request
      description: Delete a channel ownership change request. Only channel owners can delete the request.
      tags:
        - Ownership Change
      security:
        - OAuth2: []
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
      responses:
        '204':
          description: successful operation
        '400':
          description: ownership request already accepted/refused or request type mismatch
        '403':
          description: only channel owners can delete a channel ownership change request
        '404':
          description: channel ownership change not found

  '/api/v1/video-channels/{channelHandle}/ownership':
    get:
      summary: List ownership change requests for a channel
      description: List all ownership change requests for a specific channel. The authenticated user must be able to manage the channel.
      tags:
        - Ownership Change
      security:
        - OAuth2: []
      parameters:
        - $ref: '#/components/parameters/channelHandle'
        - name: state
          in: query
          required: false
          description: Filter by ownership change state
          schema:
            $ref: '#/components/schemas/ChangeOwnershipState'
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - name: sort
          in: query
          required: false
          schema:
            type: string
            enum:
              - -createdAt
              - createdAt
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  total:
                    type: integer
                    example: 1
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/ChangeOwnership'
        '400':
          description: invalid parameters
        '403':
          description: cannot manage the channel
        '404':
          description: channel not found

  '/api/v1/video-channels/{channelHandle}/give-ownership':
    post:
      summary: Request channel ownership change
      tags:
        - Ownership Change
      security:
        - OAuth2: []
      parameters:
        - $ref: '#/components/parameters/channelHandle'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                username:
                  type: string
              required:
                - username
      responses:
        '204':
          description: successful operation
        '400':
          description: changing channel ownership to this target is invalid or there is already a pending ownership request
        '403':
          description: cannot change ownership of this channel
        '404':
          description: channel not found

  '/api/v1/videos/{id}/token':
    post:
      summary: Request video token
      operationId: requestVideoToken
      description: Request special tokens that expire quickly to use them in some context (like accessing private static files)
      tags:
        - Video
      security:
        - OAuth2: []
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
        - $ref: '#/components/parameters/videoPasswordHeader'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VideoTokenResponse'
        '400':
          description: incorrect parameters
        '404':
          description: video not found

  /api/v1/videos/{id}/studio/edit:
    post:
      summary: Create a studio task
      tags:
        - Video Transcoding
        - Video
      description: Create a task to edit a video (cut, add intro/outro etc). By default the video is edited in place. Set `saveAsNewVideo` to keep it untouched and save the result in a new video.
      security:
        - OAuth2: []
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required:
                - tasks
              properties:
                tasks:
                  $ref: '#/components/schemas/VideoStudioCreateTask'
                saveAsNewVideo:
                  type: boolean
                  default: false
                  description: >
                    Keep the source video untouched: duplicate it, and edit the duplicate.
                    The duplicate is created private, in the same channel as the source video, with the source video metadata.
                    The size of the source video counts towards the user quota.
      responses:
        '200':
          description: successful operation, when `saveAsNewVideo` is `true`. Returns the identifiers of the new video
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VideoUploadResponse'
        '204':
          description: successful operation, when the source video is edited in place
        '400':
          description: incorrect parameters
        '403':
          description: the user cannot manage this video, or `saveAsNewVideo` is `true` on a blocked video and the user cannot manage blocks
        '409':
          description: video is already being processed
        '404':
          description: video not found

  /api/v1/videos/{id}/duplicate:
    post:
      summary: Duplicate a video
      operationId: duplicateVideo
      tags:
        - Video
      description: |
        Create a copy of a local video, in the same channel.

        The copy of a blocked video (that only moderators can duplicate) is blocked for the same reason.
      security:
        - OAuth2: []
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  minLength: 3
                  maxLength: 120
                  description: Name of the copy. Defaults to the name of the source video followed by "(Copy)"
      responses:
        '200':
          description: successful operation. Returns the identifiers of the new video
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VideoUploadResponse'
        '400':
          description: incorrect parameters
        '403':
          description: the user cannot manage this video, the video is not local, or the video is blocked and the user cannot manage blocks
        '404':
          description: video not found
        '409':
          description: video is already being processed
        '413':
          description: the user video quota is exceeded

  /api/v1/videos:
    get:
      summary: List videos
      operationId: getVideos
      tags:
        - Video
      parameters:
        # Common video filter parameters
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/skipCount'
        - $ref: '#/components/parameters/videosSort'
        - $ref: '#/components/parameters/nsfw'
        - $ref: '#/components/parameters/nsfwFlagsIncluded'
        - $ref: '#/components/parameters/nsfwFlagsExcluded'
        - $ref: '#/components/parameters/aiUsageOneOf'
        - $ref: '#/components/parameters/isLive'
        - $ref: '#/components/parameters/includeScheduledLive'
        - $ref: '#/components/parameters/categoryOneOf'
        - $ref: '#/components/parameters/licenceOneOf'
        - $ref: '#/components/parameters/languageOneOf'
        - $ref: '#/components/parameters/tagsOneOf'
        - $ref: '#/components/parameters/tagsAllOf'
        - $ref: '#/components/parameters/isLocal'
        - $ref: '#/components/parameters/include'
        - $ref: '#/components/parameters/hasHLSFiles'
        - $ref: '#/components/parameters/hasWebVideoFiles'
        - $ref: '#/components/parameters/host'
        - $ref: '#/components/parameters/autoTagOneOfVideo'
        - $ref: '#/components/parameters/stateOneOfVideo'
        - $ref: '#/components/parameters/privacyOneOf'
        - $ref: '#/components/parameters/excludeAlreadyWatched'
        - $ref: '#/components/parameters/search'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VideoListResponse'

  /api/v1/recommendations/videos:
    get:
      summary: List recommended videos
      description: |
        Return videos recommended next to a reference video (or general recommendations if no reference video is given).

        PeerTube decides the recommendation algorithm: it currently lists videos sharing tags with the reference video
        (excluding videos already watched by the authenticated user), then the latest videos.
        All returned videos are restricted to the `scope`, which defaults to the `recommendationScope` of the reference video.
      operationId: getRecommendationVideos
      tags:
        - Video
      parameters:
        - name: scope
          in: query
          required: false
          description: |
            Restrict recommended videos. Defaults to the `recommendationScope` of the reference video, or to `1` (all videos) if no reference video is given
          schema:
            $ref: '#/components/schemas/VideoRecommendationScopeSet'
        - name: videoId
          in: query
          required: false
          description: Reference video. Required if `scope` is `3` or `4`
          schema:
            oneOf:
              - $ref: '#/components/schemas/id'
              - $ref: '#/components/schemas/UUIDv4'
              - $ref: '#/components/schemas/shortUUID'
        - name: count
          in: query
          required: false
          description: Number of videos to return
          schema:
            type: integer
            minimum: 1
            maximum: 30
            default: 10
        - name: excludeVideoIds
          in: query
          required: false
          description: Videos that must not be recommended (the reference video is always excluded)
          style: form
          explode: true
          schema:
            type: array
            maxItems: 50
            items:
              $ref: '#/components/schemas/id'
        - $ref: '#/components/parameters/videoPasswordHeader'
        - $ref: '#/components/parameters/nsfw'
        - $ref: '#/components/parameters/nsfwFlagsIncluded'
        - $ref: '#/components/parameters/nsfwFlagsExcluded'
        - $ref: '#/components/parameters/aiUsageOneOf'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VideoListResponse'
        '400':
          description: invalid parameters or missing `videoId`
        '401':
          description: reference video requires authentication or a password
        '403':
          description: reference video is not visible by the user or the password is invalid
        '404':
          description: reference video not found

  /api/v1/videos/categories:
    get:
      summary: List available video categories
      operationId: getCategories
      tags:
        - Video
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: array
                items:
                  type: string
              examples:
                nightly:
                  externalValue: https://peertube2.cpy.re/api/v1/videos/categories

  /api/v1/videos/licences:
    get:
      summary: List available video licences
      operationId: getLicences
      tags:
        - Video
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: array
                items:
                  type: string
              examples:
                nightly:
                  externalValue: https://peertube2.cpy.re/api/v1/videos/licences

  /api/v1/videos/languages:
    get:
      summary: List available video languages
      operationId: getLanguages
      tags:
        - Video
      parameters:
        - name: scope
          in: query
          description: "**PeerTube >= 8.2** Filter languages by scope. Use `subtitle` to exclude sign languages and other languages that don't make sense for subtitles."
          required: false
          schema:
            type: string
            enum:
              - subtitle
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: array
                items:
                  type: string
              examples:
                nightly:
                  externalValue: https://peertube2.cpy.re/api/v1/videos/languages

  /api/v1/videos/privacies:
    get:
      summary: List available video privacy policies
      operationId: getVideoPrivacyPolicies
      tags:
        - Video
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: array
                items:
                  type: string
              examples:
                nightly:
                  externalValue: https://peertube2.cpy.re/api/v1/videos/privacies

  '/api/v1/videos/{id}':
    put:
      summary: Update a video
      operationId: putVideo
      security:
        - OAuth2: []
      tags:
        - Video
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
      responses:
        '204':
          description: successful operation
      requestBody:
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                channelId:
                  type: integer
                  description:
                    New channel of the video. The channel must be owned by the same account as the previous one.
                    Use the "change ownership" endpoints to give a video to a channel owned by another account on the local PeerTube instance.
                thumbnailfile:
                  description: Video thumbnail file
                  type: string
                  format: binary
                previewfile:
                  description: Deprecated in PeerTube v8.1, use thumbnailfile instead
                  deprecated: true
                  type: string
                  format: binary
                category:
                  $ref: '#/components/schemas/VideoCategorySet'
                licence:
                  $ref: '#/components/schemas/VideoLicenceSet'
                language:
                  $ref: '#/components/schemas/VideoLanguageSet'
                privacy:
                  $ref: '#/components/schemas/VideoPrivacySet'
                description:
                  description: Video description
                  type: string
                waitTranscoding:
                  description: Whether or not we wait transcoding before publish the video
                  type: string
                support:
                  description: A text tell the audience how to support the video creator
                  example: Please support our work on https://soutenir.framasoft.org/en/ <3
                  type: string
                nsfw:
                  description: Whether or not this video contains sensitive content
                  type: boolean
                nsfwSummary:
                  description: More information about the sensitive content of the video
                nsfwFlags:
                  $ref: '#/components/schemas/NSFWFlag'
                name:
                  description: Video name
                  type: string
                  minLength: 3
                  maxLength: 120
                tags:
                  description: Video tags (maximum 5 tags each between 2 and 30 characters)
                  type: array
                  minItems: 1
                  maxItems: 5
                  items:
                    type: string
                    minLength: 2
                    maxLength: 30
                commentsPolicy:
                  $ref: '#/components/schemas/VideoCommentsPolicySet'
                recommendationScope:
                  $ref: '#/components/schemas/VideoRecommendationScopeSet'
                aiUsage:
                  $ref: '#/components/schemas/VideoAIUsageSet'
                commercialContent:
                  $ref: '#/components/schemas/VideoCommercialContentSet'
                downloadEnabled:
                  description: Enable or disable downloading for this video
                  type: boolean
                originallyPublishedAt:
                  description: Date when the content was originally published
                  type: string
                  format: date-time
                  nullable: true
                scheduleUpdate:
                  $ref: '#/components/schemas/VideoScheduledUpdate'
                videoPasswords:
                  $ref: '#/components/schemas/AddVideoPasswords'
            encoding:
              thumbnailfile:
                contentType: image/jpeg
              previewfile:
                contentType: image/jpeg
              tags:
                style: form
                explode: true
    get:
      summary: Get a video
      operationId: getVideo
      tags:
        - Video
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
        - $ref: '#/components/parameters/videoPasswordHeader'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VideoDetails'
        '401':
          description: Requires authentication or the video requires a password
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ServerError'
        '403':
          description: Invalid authentication or the video requires a password
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ServerError'
    delete:
      summary: Delete a video
      operationId: delVideo
      security:
        - OAuth2: []
      tags:
        - Video
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
      responses:
        '204':
          description: successful operation

  '/api/v1/videos/{id}/views':
    post:
      summary: Notify user is watching a video
      description: Call this endpoint regularly (every 5-10 seconds for example) to notify the server the user is watching the video. After a while, PeerTube will increase video's viewers counter. If the user is authenticated, PeerTube will also store the current player time.
      operationId: addView
      tags:
        - Video
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UserViewingVideo'
        required: true
      responses:
        '204':
          description: successful operation

  '/api/v1/videos/{id}/stats/overall':
    get:
      summary: Get overall stats of a video
      tags:
        - Video Stats
      security:
        - OAuth2: []
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
        - name: startDate
          in: query
          description: Filter stats by start date
          schema:
            type: string
            format: date-time
        - name: endDate
          in: query
          description: Filter stats by end date
          schema:
            type: string
            format: date-time
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VideoStatsOverall'

  '/api/v1/videos/{id}/stats/user-agent':
    get:
      summary: Get user agent stats of a video
      tags:
        - Video Stats
      security:
        - OAuth2: []
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
        - name: startDate
          in: query
          description: Filter stats by start date
          schema:
            type: string
            format: date-time
        - name: endDate
          in: query
          description: Filter stats by end date
          schema:
            type: string
            format: date-time
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VideoStatsUserAgent'

  '/api/v1/videos/{id}/stats/retention':
    get:
      summary: Get retention stats of a video
      tags:
        - Video Stats
      security:
        - OAuth2: []
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VideoStatsRetention'

  '/api/v1/videos/{id}/stats/timeseries/{metric}':
    get:
      summary: Get timeserie stats of a video
      tags:
        - Video Stats
      security:
        - OAuth2: []
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
        -
          name: metric
          in: path
          required: true
          description: The metric to get
          schema:
            type: string
            enum:
              - 'viewers'
              - 'aggregateWatchTime'
        - name: startDate
          in: query
          description: Filter stats by start date
          schema:
            type: string
            format: date-time
        - name: endDate
          in: query
          description: Filter stats by end date
          schema:
            type: string
            format: date-time
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VideoStatsTimeserie'

  /api/v1/videos/upload:
    post:
      summary: Upload a video
      description: Uses a single request to upload a video.
      operationId: uploadLegacy
      security:
        - OAuth2: []
      tags:
        - Video
        - Video Upload
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VideoUploadResponse'
        '403':
          description: video didn't pass upload filter
        '408':
          description: upload has timed out
        '413':
          x-summary: video file too large, due to quota or max body size limit set by the reverse-proxy
          description: |
            If the response has no body, it means the reverse-proxy didn't let it through. Otherwise disambiguate via `code`:
            - `quota_reached` for quota limits whether daily or global
          headers:
            X-File-Maximum-Size:
              schema:
                type: string
                format: Nginx size
              description: Maximum file size for the video
        '415':
          description: video type unsupported
        '422':
          description: video unreadable
      requestBody:
        content:
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/VideoUploadRequestLegacy'
            encoding:
              videofile:
                contentType: video/mp4, video/webm, video/ogg, video/avi, video/quicktime, video/x-msvideo, video/x-flv, video/x-matroska, application/octet-stream
              thumbnailfile:
                contentType: image/jpeg
              previewfile:
                contentType: image/jpeg
      x-codeSamples:
        - lang: Shell
          source: |
            ## DEPENDENCIES: jq
            USERNAME="<your_username>"
            PASSWORD="<your_password>"
            FILE_PATH="<your_file_path>"
            CHANNEL_ID="<your_channel_id>"
            NAME="<video_name>"
            API="https://peertube2.cpy.re/api/v1"

            ## AUTH
            client_id=$(curl -s "$API/oauth-clients/local" | jq -r ".client_id")
            client_secret=$(curl -s "$API/oauth-clients/local" | jq -r ".client_secret")
            token=$(curl -s "$API/users/token" \
              --data client_id="$client_id" \
              --data client_secret="$client_secret" \
              --data grant_type=password \
              --data username="$USERNAME" \
              --data password="$PASSWORD" \
              | jq -r ".access_token")

            ## VIDEO UPLOAD
            curl -s "$API/videos/upload" \
              -H "Authorization: Bearer $token" \
              --max-time 600 \
              --form videofile=@"$FILE_PATH" \
              --form channelId=$CHANNEL_ID \
              --form name="$NAME"

  /api/v1/videos/upload-resumable:
    post:
      summary: Initialize the resumable upload of a video
      description: Uses [a resumable protocol](https://github.com/kukhariev/node-uploadx/blob/master/proto.md) to initialize the upload of a video
      operationId: uploadResumableInit
      security:
        - OAuth2: []
      tags:
        - Video
        - Video Upload
      parameters:
        - $ref: '#/components/parameters/resumableUploadInitContentLengthHeader'
        - $ref: '#/components/parameters/resumableUploadInitContentTypeHeader'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/VideoUploadRequestResumable'
      responses:
        '200':
          description: file already exists, send a [`resume`](https://github.com/kukhariev/node-uploadx/blob/master/proto.md) request instead
        '201':
          description: created
          headers:
            Location:
              schema:
                type: string
                format: url
                example: /api/v1/videos/upload-resumable?upload_id=471e97554f21dec3b8bb5d4602939c51
            Content-Length:
              schema:
                type: number
                example: 0
        '413':
          x-summary: video file too large, due to quota, absolute max file size or concurrent partial upload limit
          description: |
            Disambiguate via `code`:
            - `max_file_size_reached` for the absolute file size limit
            - `quota_reached` for quota limits whether daily or global
        '415':
          description: video type unsupported
    put:
      summary: Send chunk for the resumable upload of a video
      description: Uses [a resumable protocol](https://github.com/kukhariev/node-uploadx/blob/master/proto.md) to continue, pause or resume the upload of a video
      operationId: uploadResumable
      security:
        - OAuth2: []
      tags:
        - Video
        - Video Upload
      parameters:
        - $ref: '#/components/parameters/resumableUploadId'
        - $ref: '#/components/parameters/resumableUploadChunkContentRangeHeader'
        - $ref: '#/components/parameters/resumableUploadChunkContentLengthHeader'
      requestBody:
        content:
          application/octet-stream:
            schema:
              type: string
              format: binary
      responses:
        '200':
          description: last chunk received
          headers:
            Content-Length:
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VideoUploadResponse'
        '308':
          description: resume incomplete
          headers:
            Range:
              schema:
                type: string
                example: bytes=0-262143
            Content-Length:
              schema:
                type: number
                example: 0
        '400':
          description: chunk is smaller than `client.videos.resumableUpload.minChunkSize` of the server config or 1/10,000 of the file size (and is not the last one)
        '403':
          description: video didn't pass upload filter
        '404':
          description: upload not found
        '409':
          description: chunk doesn't match range
        '422':
          description: video unreadable
        '429':
          description: too many concurrent requests
        '503':
          description: upload is already being processed
          headers:
            'Retry-After':
              schema:
                type: number
                example: 300
    delete:
      summary: Cancel the resumable upload of a video, deleting any data uploaded so far
      description: Uses [a resumable protocol](https://github.com/kukhariev/node-uploadx/blob/master/proto.md) to cancel the upload of a video
      operationId: uploadResumableCancel
      security:
        - OAuth2: []
      tags:
        - Video
        - Video Upload
      parameters:
        - $ref: '#/components/parameters/resumableUploadId'
        - name: Content-Length
          in: header
          required: true
          schema:
            type: number
            example: 0
      responses:
        '204':
          description: upload cancelled
          headers:
            Content-Length:
              schema:
                type: number
                example: 0
        '404':
          description: upload not found

  /api/v1/videos/imports:
    post:
      summary: Import a video
      description: Import a torrent or magnetURI or HTTP resource (if enabled by the instance administrator)
      operationId: importVideo
      security:
        - OAuth2: []
      tags:
        - Video Imports
        - Video Upload
      requestBody:
        content:
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/VideoCreateImport'
            encoding:
              torrentfile:
                contentType: application/x-bittorrent
              thumbnailfile:
                contentType: image/jpeg
              previewfile:
                contentType: image/jpeg
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VideoUploadResponse'
        '400':
          description: '`magnetUri` or `targetUrl` or a torrent file missing'
        '403':
          description: video didn't pass pre-import filter
        '409':
          description: HTTP or Torrent/magnetURI import not enabled

  /api/v1/videos/imports/{id}/cancel:
    post:
      summary: Cancel video import
      description: Cancel a pending video import
      security:
        - OAuth2: []
      tags:
        - Video Imports
      parameters:
        - $ref: '#/components/parameters/id'
      responses:
        '204':
          description: successful operation

  /api/v1/videos/imports/{id}/retry:
    post:
      summary: Retry video import
      description: "**PeerTube >= 8.0** Retry a failed or cancelled (**PeerTube >= 8.3**) video import"
      security:
        - OAuth2: []
      tags:
        - Video Imports
      parameters:
        - $ref: '#/components/parameters/id'
      responses:
        '204':
          description: successful operation

  /api/v1/videos/imports/{id}:
    delete:
      summary: Delete video import
      description: Delete ended video import
      security:
        - OAuth2: []
      tags:
        - Video Imports
      parameters:
        - $ref: '#/components/parameters/id'
      responses:
        '204':
          description: successful operation

  /api/v1/videos/live:
    post:
      summary: Create a live
      operationId: addLive
      security:
        - OAuth2: []
      tags:
        - Live Videos
        - Video
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VideoUploadResponse'
        '400':
          x-summary: validation error, or conflicting `saveReplay` and `permanentLive` parameter set
          description: |
            Disambiguate via `code`:
            - default type for a validation error
            - `live_conflicting_permanent_and_save_replay` for conflicting parameters set
        '403':
          x-summary: live is not enabled, allow replay is not enabled, or max instance/user live videos limit is exceeded
          description: |
            Disambiguate via `code`:
            - `live_not_enabled` for a disabled live feature
            - `live_not_allowing_replay` for a disabled replay feature
            - `max_instance_lives_limit_reached` for the absolute concurrent live limit
            - `max_user_lives_limit_reached` for the user concurrent live limit
      requestBody:
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                channelId:
                  description: Channel id that will contain this live video
                  type: integer
                saveReplay:
                  type: boolean
                replaySettings:
                  $ref: '#/components/schemas/LiveVideoReplaySettings'
                permanentLive:
                  description: User can stream multiple times in a permanent live
                  type: boolean
                latencyMode:
                  description: User can select live latency mode if enabled by the instance
                  allOf:
                    - $ref: '#/components/schemas/LiveVideoLatencyMode'
                thumbnailfile:
                  description: Live video/replay thumbnail file
                  type: string
                  format: binary
                previewfile:
                  description: Deprecated in PeerTube v8.1, use thumbnailfile instead
                  deprecated: true
                  type: string
                  format: binary
                privacy:
                  $ref: '#/components/schemas/VideoPrivacySet'
                category:
                  $ref: '#/components/schemas/VideoCategorySet'
                licence:
                  $ref: '#/components/schemas/VideoLicenceSet'
                language:
                  $ref: '#/components/schemas/VideoLanguageSet'
                description:
                  description: Live video/replay description
                  type: string
                support:
                  description: A text tell the audience how to support the creator
                  example: Please support our work on https://soutenir.framasoft.org/en/ <3
                  type: string
                nsfw:
                  description: Whether or not this live video/replay contains sensitive content
                  type: boolean
                nsfwSummary:
                  description: More information about the sensitive content of the video
                nsfwFlags:
                  $ref: '#/components/schemas/NSFWFlag'
                name:
                  description: Live video/replay name
                  type: string
                  minLength: 3
                  maxLength: 120
                tags:
                  description: Live video/replay tags (maximum 5 tags each between 2 and 30 characters)
                  type: array
                  minItems: 1
                  maxItems: 5
                  items:
                    type: string
                    minLength: 2
                    maxLength: 30
                commentsPolicy:
                  $ref: '#/components/schemas/VideoCommentsPolicySet'
                recommendationScope:
                  $ref: '#/components/schemas/VideoRecommendationScopeSet'
                aiUsage:
                  $ref: '#/components/schemas/VideoAIUsageSet'
                commercialContent:
                  $ref: '#/components/schemas/VideoCommercialContentSet'
                downloadEnabled:
                  description: Enable or disable downloading for the replay of this live video
                  type: boolean
                schedules:
                  type: array
                  items:
                    $ref: '#/components/schemas/LiveSchedule'
              required:
                - channelId
                - name
            encoding:
              thumbnailfile:
                contentType: image/jpeg
              previewfile:
                contentType: image/jpeg

  /api/v1/videos/live/{id}:
    get:
      summary: Get information about a live
      operationId: getLiveId
      security:
        - OAuth2: []
      tags:
        - Live Videos
        - Video
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LiveVideoResponse'
    put:
      summary: Update information about a live
      operationId: updateLiveId
      security:
        - OAuth2: []
      tags:
        - Live Videos
        - Video
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/LiveVideoUpdate'
      responses:
        '204':
          description: successful operation
        '400':
          description: bad parameters or trying to update a live that has already started
        '403':
          description: trying to save replay of the live but saving replay is not enabled on the instance
  /api/v1/videos/live/{id}/sessions:
    get:
      summary: List live sessions
      description: List all sessions created in a particular live
      security:
        - OAuth2: []
      tags:
        - Live Videos
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
        - $ref: '#/components/parameters/sort'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  total:
                    type: integer
                    example: 1
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/LiveVideoSessionResponse'
  /api/v1/videos/{id}/live-session:
    get:
      summary: Get live session of a replay
      description: If the video is a replay of a live, you can find the associated live session using this endpoint
      security:
        - OAuth2: []
      tags:
        - Live Videos
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
        - $ref: '#/components/parameters/videoPasswordHeader'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LiveVideoSessionResponse'

  '/api/v1/videos/{id}/source':
    get:
      summary: Get video source file metadata
      description: Get metadata and download link of original video file
      operationId: getVideoSource
      security:
        - OAuth2: []
      tags:
        - Video
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VideoSource'

  '/api/v1/videos/{id}/source/file':
    delete:
      summary: Delete video source file
      operationId: deleteVideoSourceFile
      tags:
        - Video
      security:
        - OAuth2:
          - admin
          - moderator
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
      responses:
        '204':
          description: successful operation
        '404':
          description: video source not found

  '/api/v1/videos/{id}/source/replace-resumable':
    post:
      summary: Initialize the resumable replacement of a video
      description: "**PeerTube >= 6.0** Uses [a resumable protocol](https://github.com/kukhariev/node-uploadx/blob/master/proto.md) to initialize the replacement of a video"
      operationId: replaceVideoSourceResumableInit
      security:
        - OAuth2: []
      tags:
        - Video
        - Video Upload
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
        - $ref: '#/components/parameters/resumableUploadInitContentLengthHeader'
        - $ref: '#/components/parameters/resumableUploadInitContentTypeHeader'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/VideoReplaceSourceRequestResumable'
      responses:
        '200':
          description: file already exists, send a [`resume`](https://github.com/kukhariev/node-uploadx/blob/master/proto.md) request instead
        '201':
          description: created
          headers:
            Location:
              schema:
                type: string
                format: url
            Content-Length:
              schema:
                type: number
                example: 0
        '413':
          x-summary: video file too large, due to quota, absolute max file size or concurrent partial upload limit
          description: |
            Disambiguate via `code`:
            - `max_file_size_reached` for the absolute file size limit
            - `quota_reached` for quota limits whether daily or global
        '415':
          description: video type unsupported
    put:
      summary: Send chunk for the resumable replacement of a video
      description: "**PeerTube >= 6.0** Uses [a resumable protocol](https://github.com/kukhariev/node-uploadx/blob/master/proto.md) to continue, pause or resume the replacement of a video"
      operationId: replaceVideoSourceResumable
      security:
        - OAuth2: []
      tags:
        - Video
        - Video Upload
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
        - $ref: '#/components/parameters/resumableUploadId'
        - $ref: '#/components/parameters/resumableUploadChunkContentRangeHeader'
        - $ref: '#/components/parameters/resumableUploadChunkContentLengthHeader'
      requestBody:
        content:
          application/octet-stream:
            schema:
              type: string
              format: binary
      responses:
        '204':
          description: 'last chunk received: successful operation'
        '308':
          description: resume incomplete
          headers:
            Range:
              schema:
                type: string
                example: bytes=0-262143
            Content-Length:
              schema:
                type: number
                example: 0
        '400':
          description: chunk is smaller than `client.videos.resumableUpload.minChunkSize` of the server config or 1/10,000 of the file size (and is not the last one)
        '403':
          description: video didn't pass file replacement filter
        '404':
          description: replace upload not found
        '409':
          description: chunk doesn't match range
        '422':
          description: video unreadable
        '429':
          description: too many concurrent requests
        '503':
          description: upload is already being processed
          headers:
            'Retry-After':
              schema:
                type: number
                example: 300
    delete:
      summary: Cancel the resumable replacement of a video
      description: "**PeerTube >= 6.0** Uses [a resumable protocol](https://github.com/kukhariev/node-uploadx/blob/master/proto.md) to cancel the replacement of a video"
      operationId: replaceVideoSourceResumableCancel
      security:
        - OAuth2: []
      tags:
        - Video
        - Video Upload
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
        - $ref: '#/components/parameters/resumableUploadId'
        - name: Content-Length
          in: header
          required: true
          schema:
            type: number
            example: 0
      responses:
        '204':
          description: source file replacement cancelled
          headers:
            Content-Length:
              schema:
                type: number
                example: 0
        '404':
          description: source file replacement not found

  /api/v1/users/me/abuses:
    get:
      summary: List my abuses
      operationId: getMyAbuses
      security:
        - OAuth2: []
      tags:
        - Abuses
        - My User
      parameters:
        - name: id
          in: query
          description: only list the report with this id
          schema:
            type: integer
        - name: state
          in: query
          schema:
            $ref: '#/components/schemas/AbuseStateSet'
        - $ref: '#/components/parameters/abusesSort'
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  total:
                    type: integer
                    example: 1
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Abuse'

  /api/v1/abuses:
    get:
      summary: List abuses
      operationId: getAbuses
      security:
        - OAuth2:
          - admin
          - moderator
      tags:
        - Abuses
      parameters:
        - name: id
          in: query
          description: only list the report with this id
          schema:
            type: integer
        - name: predefinedReason
          in: query
          description: predefined reason the listed reports should contain
          schema:
            $ref: '#/components/schemas/PredefinedAbuseReasons'
        - name: search
          in: query
          description: plain search that will match with video titles, reporter names and more
          schema:
            type: string
        - name: state
          in: query
          schema:
            $ref: '#/components/schemas/AbuseStateSet'
        - name: searchReporter
          in: query
          description: only list reports of a specific reporter
          schema:
            type: string
        - name: searchReportee
          description: only list reports of a specific reportee
          in: query
          schema:
            type: string
        - name: searchVideo
          in: query
          description: only list reports of a specific video
          schema:
            type: string
        - name: searchVideoChannel
          in: query
          description: only list reports of a specific video channel
          schema:
            type: string
        - name: videoIs
          in: query
          description: only list deleted or blocklisted videos
          schema:
            type: string
            enum:
            - 'deleted'
            - 'blacklisted'
        - name: filter
          in: query
          description: only list account, comment or video reports
          schema:
            type: string
            enum:
            - 'video'
            - 'comment'
            - 'account'
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/abusesSort'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  total:
                    type: integer
                    example: 1
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Abuse'
    post:
      summary: Report an abuse
      description: >
        You cannot report a video that you own or on which you are a collaborator (video channel editor).
      security:
        - OAuth2: []
      tags:
        - Abuses
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                reason:
                  description: Reason why the user reports this video
                  type: string
                  minLength: 2
                  maxLength: 3000
                predefinedReasons:
                  $ref: '#/components/schemas/PredefinedAbuseReasons'
                video:
                  type: object
                  properties:
                    id:
                      description: Video id to report
                      allOf:
                        - $ref: '#/components/schemas/Video/properties/id'
                    startAt:
                      type: integer
                      format: seconds
                      description: Timestamp in the video that marks the beginning of the report
                      minimum: 0
                    endAt:
                      type: integer
                      format: seconds
                      description: Timestamp in the video that marks the ending of the report
                      minimum: 0
                comment:
                  type: object
                  properties:
                    id:
                      description: Comment id to report
                      allOf:
                        - $ref: '#/components/schemas/VideoComment/properties/id'
                account:
                  type: object
                  properties:
                    id:
                      description: Account id to report
                      type: integer
              required:
                - reason
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  abuse:
                    type: object
                    properties:
                      id:
                        $ref: '#/components/schemas/id'
        '400':
          description: incorrect request parameters
        '403':
          description: cannot report a video you own or that you collaborate on

  '/api/v1/abuses/{abuseId}':
    put:
      summary: Update an abuse
      security:
        - OAuth2:
          - admin
          - moderator
      tags:
        - Abuses
      parameters:
        - $ref: '#/components/parameters/abuseId'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                state:
                  $ref: '#/components/schemas/AbuseStateSet'
                moderationComment:
                  type: string
                  description: Update the report comment visible only to the moderation team
                  minLength: 2
                  maxLength: 3000
      responses:
        '204':
          description: successful operation
        '404':
          description: abuse not found
    delete:
      tags:
        - Abuses
      summary: Delete an abuse
      security:
        - OAuth2:
          - admin
          - moderator
      parameters:
        - $ref: '#/components/parameters/abuseId'
      responses:
        '204':
          description: successful operation
        '404':
          description: block not found

  '/api/v1/abuses/{abuseId}/messages':
    get:
      summary: List messages of an abuse
      security:
        - OAuth2: []
      tags:
        - Abuses
      parameters:
        - $ref: '#/components/parameters/abuseId'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  total:
                    type: integer
                    example: 1
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/AbuseMessage'
    post:
      summary: Add message to an abuse
      security:
        - OAuth2: []
      tags:
        - Abuses
      parameters:
        - $ref: '#/components/parameters/abuseId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                message:
                  description: Message to send
                  type: string
                  minLength: 2
                  maxLength: 3000
              required:
                - message
      responses:
        '200':
          description: successful operation
        '400':
          description: incorrect request parameters

  '/api/v1/abuses/{abuseId}/messages/{abuseMessageId}':
    delete:
      summary: Delete an abuse message
      security:
        - OAuth2: []
      tags:
        - Abuses
      parameters:
        - $ref: '#/components/parameters/abuseId'
        - $ref: '#/components/parameters/abuseMessageId'
      responses:
        '204':
          description: successful operation

  '/api/v1/videos/{id}/blacklist':
    post:
      summary: Block a video
      operationId: addVideoBlock
      security:
        - OAuth2:
          - admin
          - moderator
      tags:
        - Video Blocks
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/VideoBlacklistCreate'
      responses:
        '204':
          description: successful operation
    put:
      summary: Update a video block
      operationId: updateVideoBlock
      security:
        - OAuth2:
          - admin
          - moderator
      tags:
        - Video Blocks
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/VideoBlacklistUpdate'
      responses:
        '204':
          description: successful operation
        '404':
          description: block not found
    delete:
      summary: Unblock a video by its id
      operationId: delVideoBlock
      security:
        - OAuth2:
          - admin
          - moderator
      tags:
        - Video Blocks
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
      responses:
        '204':
          description: successful operation
        '404':
          description: block not found

  /api/v1/videos/blacklist:
    get:
      tags:
        - Video Blocks
      summary: List video blocks
      operationId: getVideoBlocks
      security:
        - OAuth2:
          - admin
          - moderator
      parameters:
        - name: type
          in: query
          description: >
            list only blocks that match this type:

            - `1`: manual block

            - `2`: automatic block that needs review
          schema:
            type: integer
            enum:
              - 1
              - 2
        - name: search
          in: query
          description: plain search that will match with video titles, and more
          schema:
            type: string
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/blacklistsSort'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  total:
                    type: integer
                    example: 1
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/VideoBlacklist'

  /api/v1/videos/{id}/storyboards:
    get:
      summary: List storyboards of a video
      description: "**PeerTube >= 6.0**"
      operationId: listVideoStoryboards
      tags:
        - Video
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  storyboards:
                    type: array
                    items:
                      $ref: '#/components/schemas/Storyboard'

  /api/v1/videos/{id}/captions:
    get:
      summary: List captions of a video
      operationId: getVideoCaptions
      tags:
        - Video Captions
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
        - $ref: '#/components/parameters/videoPasswordHeader'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  total:
                    type: integer
                    example: 1
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/VideoCaption'

  /api/v1/videos/{id}/captions/generate:
    post:
      summary: Generate a video caption
      operationId: generateVideoCaption
      description: "**PeerTube >= 6.2** This feature has to be enabled by the administrator"
      security:
        - OAuth2:
          - user
      tags:
        - Video Captions
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                forceTranscription:
                  type: boolean
                  default: false
      responses:
        '204':
          description: successful operation
        '404':
          description: video not found


  /api/v1/videos/{id}/captions/{captionLanguage}:
    put:
      summary: Add or replace a video caption
      operationId: addVideoCaption
      security:
        - OAuth2:
          - user
      tags:
        - Video Captions
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
        - $ref: '#/components/parameters/captionLanguage'
      requestBody:
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                captionfile:
                  description: The file to upload.
                  type: string
                  format: binary
            encoding:
              captionfile:
                contentType: text/vtt, application/x-subrip, text/plain
      responses:
        '204':
          description: successful operation
        '404':
          description: video or language not found
    delete:
      summary: Delete a video caption
      operationId: delVideoCaption
      security:
        - OAuth2:
          - user
      tags:
        - Video Captions
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
        - $ref: '#/components/parameters/captionLanguage'
      responses:
        '204':
          description: successful operation
        '404':
          description: video or language or caption for that language not found

  /api/v1/videos/{id}/chapters:
    get:
      summary: Get chapters of a video
      description: "**PeerTube >= 6.0**"
      operationId: getVideoChapters
      tags:
        - Video Chapters
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
        - $ref: '#/components/parameters/videoPasswordHeader'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VideoChapters'
    put:
      summary: Replace video chapters
      description: "**PeerTube >= 6.0**"
      operationId: replaceVideoChapters
      security:
        - OAuth2:
          - user
      tags:
        - Video Chapters
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                chapters:
                  type: array
                  items:
                    type: object
                    properties:
                      title:
                        type: string
                      timecode:
                        type: integer
      responses:
        '204':
          description: successful operation
        '404':
          description: video not found

  /api/v1/videos/{id}/embed-privacy:
    get:
      summary: Get video embed privacy
      description: "**PeerTube >= 8.1**"
      operationId: getVideoEmbedPrivacy
      security:
        - OAuth2:
          - user
      tags:
        - Video Embed Privacy
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  policy:
                    type: object
                    properties:
                      id:
                        $ref: '#/components/schemas/VideoEmbedPrivacy'
                      label:
                        type: string
                        example: Allowlist
                  domains:
                    type: array
                    items:
                      type: string
                      example: 'example.com'
        '400':
          description: invalid request
    put:
      summary: Update video embed privacy
      description: "**PeerTube >= 8.1**"
      operationId: updateVideoEmbedPrivacy
      security:
        - OAuth2:
          - user
      tags:
        - Video Embed Privacy
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                policy:
                  $ref: '#/components/schemas/VideoEmbedPrivacy'
                domains:
                  type: array
                  items:
                    type: string
                    example: 'example.com'
      responses:
        '204':
          description: successful operation
        '400':
          description: invalid request

  /api/v1/videos/{id}/embed-privacy/allowed:
    get:
      summary: Check if embed is allowed
      description: "**PeerTube >= 8.1** Check if video embed is allowed on a specific domain according to the video embed privacy settings"
      operationId: isVideoEmbedOnDomainAllowed
      security:
        - OAuth2:
          - user
      tags:
        - Video Embed Privacy
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
        - name: domain
          in: query
          required: true
          schema:
            type: string
          description: The domain to check if embed is allowed
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  domainAllowed:
                    type: boolean
                  userBypassAllowed:
                    description: Whether the user can bypass embed restrictions for this video, either because they are the owner/editor of the video or because they have a moderator or admin role
                    nullable: true
                    type: boolean
        '400':
          description: invalid request

  /api/v1/videos/{id}/passwords:
    get:
      summary: List video passwords
      description: "**PeerTube >= 6.0**"
      operationId: listVideoPasswords
      security:
        - OAuth2:
          - user
      tags:
        - Video Passwords
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/sort'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VideoPasswordList'
        '400':
          description: video is not password protected
    put:
      summary: Update video passwords
      description: "**PeerTube >= 6.0**"
      operationId: updateVideoPasswordList
      security:
        - OAuth2:
          - user
      tags:
        - Video Passwords
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                passwords:
                  $ref: '#/components/schemas/AddVideoPasswords'
      responses:
        '204':
          description: successful operation
        '400':
          description: video is not password protected
    post:
      summary: Add a video password
      description: "**PeerTube >= 8.0**"
      operationId: addVideoPassword
      security:
        - OAuth2:
          - user
      tags:
        - Video Passwords
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                password:
                  type: string
      responses:
        '204':
          description: successful operation
        '400':
          description: video is not password protected

  /api/v1/videos/{id}/passwords/{passwordId}:
    delete:
      summary: Delete a video password
      description: "**PeerTube >= 6.0**"
      operationId: removeVideoPassword
      security:
        - OAuth2:
          - user
      tags:
        - Video Passwords
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
        - $ref: '#/components/parameters/passwordId'
      responses:
        '204':
          description: successful operation
        '403':
          description: cannot delete the last password of the protected video
        '400':
          description: video is not password protected

  /api/v1/video-channels:
    get:
      summary: List video channels
      operationId: getVideoChannels
      tags:
        - Video Channels
      parameters:
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/sort'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VideoChannelList'
    post:
      summary: Create a video channel
      operationId: addVideoChannel
      security:
        - OAuth2: []
      tags:
        - Video Channels
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  videoChannel:
                    type: object
                    properties:
                      id:
                        $ref: '#/components/schemas/id'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/VideoChannelCreate'

  '/api/v1/video-channels/{channelHandle}':
    get:
      summary: Get a video channel
      operationId: getVideoChannel
      tags:
        - Video Channels
      parameters:
        - $ref: '#/components/parameters/channelHandle'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VideoChannel'
    put:
      summary: Update a video channel
      operationId: putVideoChannel
      security:
        - OAuth2: []
      tags:
        - Video Channels
      parameters:
        - $ref: '#/components/parameters/channelHandle'
      responses:
        '204':
          description: successful operation
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/VideoChannelUpdate'
    delete:
      summary: Delete a video channel
      operationId: delVideoChannel
      security:
        - OAuth2: []
      tags:
        - Video Channels
      parameters:
        - $ref: '#/components/parameters/channelHandle'
      responses:
        '204':
          description: successful operation

  '/api/v1/video-channels/{channelHandle}/videos':
    get:
      summary: List videos of a video channel
      operationId: getVideoChannelVideos
      tags:
        - Video
        - Video Channels
      parameters:
        - $ref: '#/components/parameters/channelHandle'
        # Common video filter parameters
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/skipCount'
        - $ref: '#/components/parameters/videosSort'
        - $ref: '#/components/parameters/nsfw'
        - $ref: '#/components/parameters/nsfwFlagsIncluded'
        - $ref: '#/components/parameters/nsfwFlagsExcluded'
        - $ref: '#/components/parameters/aiUsageOneOf'
        - $ref: '#/components/parameters/isLive'
        - $ref: '#/components/parameters/includeScheduledLive'
        - $ref: '#/components/parameters/categoryOneOf'
        - $ref: '#/components/parameters/licenceOneOf'
        - $ref: '#/components/parameters/languageOneOf'
        - $ref: '#/components/parameters/tagsOneOf'
        - $ref: '#/components/parameters/tagsAllOf'
        - $ref: '#/components/parameters/isLocal'
        - $ref: '#/components/parameters/include'
        - $ref: '#/components/parameters/hasHLSFiles'
        - $ref: '#/components/parameters/hasWebVideoFiles'
        - $ref: '#/components/parameters/host'
        - $ref: '#/components/parameters/autoTagOneOfVideo'
        - $ref: '#/components/parameters/stateOneOfVideo'
        - $ref: '#/components/parameters/privacyOneOf'
        - $ref: '#/components/parameters/excludeAlreadyWatched'
        - $ref: '#/components/parameters/search'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VideoListResponse'

  '/api/v1/video-channels/{channelHandle}/activities':
    get:
      summary: List activities of a video channel
      description: "**PeerTube >= 8.0**"
      operationId: listVideoChannelActivities
      tags:
        - Video Channels
      parameters:
        - $ref: '#/components/parameters/channelHandle'
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/sort'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChannelActivityListResponse'

  '/api/v1/video-channels/{channelHandle}/video-playlists':
    get:
      summary: List playlists of a channel
      tags:
        - Video Playlists
        - Video Channels
      parameters:
        - $ref: '#/components/parameters/channelHandle'
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/sort'
        - $ref: '#/components/parameters/videoPlaylistType'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  total:
                    type: integer
                    example: 1
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/VideoPlaylist'

  '/api/v1/video-channels/{channelHandle}/video-playlists/reorder':
    post:
      summary: Reorder channel playlists
      operationId: reorderVideoPlaylistsOfChannel
      security:
        - OAuth2: []
      tags:
        - Video Playlists
        - Video Channels
      parameters:
        - $ref: '#/components/parameters/channelHandle'
      responses:
        '204':
          description: successful operation
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                startPosition:
                  type: integer
                  description: 'Start position of the element to reorder'
                  minimum: 1
                insertAfterPosition:
                  type: integer
                  description: 'New position for the block to reorder, to add the block before the first element'
                  minimum: 0
                reorderLength:
                  type: integer
                  description: 'How many element from `startPosition` to reorder'
                  minimum: 1
              required:
                - startPosition
                - insertAfterPosition

  '/api/v1/video-channels/{channelHandle}/followers':
    get:
      tags:
        - Video Channels
      summary: 'List followers of a video channel'
      security:
        - OAuth2: []
      operationId: getVideoChannelFollowers
      parameters:
        - $ref: '#/components/parameters/channelHandle'
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/followersSort'
        - $ref: '#/components/parameters/search'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  total:
                    type: integer
                    example: 1
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Follow'

  '/api/v1/video-channels/{channelHandle}/avatar/pick':
    post:
      summary: Update channel avatar
      security:
        - OAuth2: []
      tags:
        - Video Channels
      parameters:
        - $ref: '#/components/parameters/channelHandle'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  avatars:
                    type: array
                    items:
                      $ref: '#/components/schemas/ActorImage'
        '413':
          description: image file too large
          headers:
            X-File-Maximum-Size:
              schema:
                type: string
                format: Nginx size
              description: Maximum file size for the avatar
      requestBody:
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                avatarfile:
                  description: The file to upload.
                  type: string
                  format: binary
            encoding:
              avatarfile:
                contentType: image/png, image/jpeg

  '/api/v1/video-channels/{channelHandle}/avatar':
    delete:
      summary: Delete channel avatar
      security:
        - OAuth2: []
      tags:
        - Video Channels
      parameters:
        - $ref: '#/components/parameters/channelHandle'
      responses:
        '204':
          description: successful operation

  '/api/v1/video-channels/{channelHandle}/banner/pick':
    post:
      summary: Update channel banner
      security:
        - OAuth2: []
      tags:
        - Video Channels
      parameters:
        - $ref: '#/components/parameters/channelHandle'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  banners:
                    type: array
                    items:
                      $ref: '#/components/schemas/ActorImage'
        '413':
          description: image file too large
          headers:
            X-File-Maximum-Size:
              schema:
                type: string
                format: Nginx size
              description: Maximum file size for the banner
      requestBody:
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                bannerfile:
                  description: The file to upload.
                  type: string
                  format: binary
            encoding:
              bannerfile:
                contentType: image/png, image/jpeg

  '/api/v1/video-channels/{channelHandle}/banner':
    delete:
      summary: Delete channel banner
      security:
        - OAuth2: []
      tags:
        - Video Channels
      parameters:
        - $ref: '#/components/parameters/channelHandle'
      responses:
        '204':
          description: successful operation

  '/api/v1/video-channels/{channelHandle}/import-videos':
    post:
      summary: Import videos in channel
      description: Import a remote channel/playlist videos into a channel
      security:
        - OAuth2: []
      tags:
        - Video Channels
        - Channels Sync
      parameters:
        - $ref: '#/components/parameters/channelHandle'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ImportVideosInChannelCreate'
      responses:
        '204':
          description: successful operation

  '/api/v1/video-channel-syncs':
    post:
      summary: Create a synchronization for a video channel
      operationId: addVideoChannelSync
      security:
        - OAuth2: []
      tags:
        - Channels Sync
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/VideoChannelSyncCreate'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  videoChannelSync:
                    $ref: "#/components/schemas/VideoChannelSync"

  '/api/v1/video-channel-syncs/{channelSyncId}':
    delete:
      summary: Delete a video channel synchronization
      operationId: delVideoChannelSync
      security:
        - OAuth2: []
      tags:
        - Channels Sync
      parameters:
        - $ref: '#/components/parameters/channelSyncId'
      responses:
        '204':
          description: successful operation

  '/api/v1/video-channel-syncs/{channelSyncId}/sync':
    post:
      summary: Triggers the channel synchronization job, fetching all the videos from the remote channel
      operationId: triggerVideoChannelSync
      security:
        - OAuth2: []
      tags:
        - Channels Sync
      parameters:
        - $ref: '#/components/parameters/channelSyncId'
      responses:
        '204':
          description: successful operation


  '/api/v1/player-settings/videos/{id}':
    get:
      summary: Get video player settings
      description: Get player settings for a specific video. Returns video-specific settings merged with channel player settings.
      operationId: getVideoPlayerSettings
      tags:
        - Player Settings
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
        - name: raw
          in: query
          required: false
          description: Return raw settings without merging channel defaults
          schema:
            type: boolean
            default: false
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlayerVideoSettings'
        '404':
          description: video not found
    put:
      summary: Update video player settings
      description: Update player settings for a specific video
      operationId: updateVideoPlayerSettings
      security:
        - OAuth2: []
      tags:
        - Player Settings
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PlayerVideoSettingsUpdate'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlayerVideoSettings'
        '404':
          description: video not found

  '/api/v1/player-settings/video-channels/{channelHandle}':
    get:
      summary: Get channel player settings
      description: Get player settings for a video channel.
      operationId: getChannelPlayerSettings
      tags:
        - Player Settings
      parameters:
        - $ref: '#/components/parameters/channelHandle'
        - name: raw
          in: query
          required: false
          description: Return raw settings without applying instance defaults
          schema:
            type: boolean
            default: false
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlayerChannelSettings'
        '404':
          description: video channel not found
    put:
      summary: Update channel player settings
      description: Update default player settings for a video channel.
      operationId: updateChannelPlayerSettings
      security:
        - OAuth2: []
      tags:
        - Player Settings
      parameters:
        - $ref: '#/components/parameters/channelHandle'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PlayerChannelSettingsUpdate'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlayerChannelSettings'
        '404':
          description: video channel not found


  /api/v1/video-playlists/privacies:
    get:
      summary: List available playlist privacy policies
      operationId: getPlaylistPrivacyPolicies
      tags:
        - Video Playlists
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: array
                items:
                  type: string
              examples:
                nightly:
                  externalValue: https://peertube2.cpy.re/api/v1/video-playlists/privacies

  /api/v1/video-playlists:
    get:
      summary: List video playlists
      operationId: getPlaylists
      tags:
        - Video Playlists
      parameters:
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/sort'
        - $ref: '#/components/parameters/videoPlaylistType'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  total:
                    type: integer
                    example: 1
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/VideoPlaylist'
    post:
      summary: Create a video playlist
      description: If the video playlist is set as public, `videoChannelId` is mandatory.
      operationId: addPlaylist
      security:
        - OAuth2: []
      tags:
        - Video Playlists
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  videoPlaylist:
                    type: object
                    properties:
                      id:
                        $ref: '#/components/schemas/VideoPlaylist/properties/id'
                      uuid:
                        $ref: '#/components/schemas/VideoPlaylist/properties/uuid'
                      shortUUID:
                        $ref: '#/components/schemas/VideoPlaylist/properties/shortUUID'
      requestBody:
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                displayName:
                  description: Video playlist display name
                  type: string
                  minLength: 1
                  maxLength: 120
                thumbnailfile:
                  description: Video playlist thumbnail file
                  type: string
                  format: binary
                privacy:
                  $ref: '#/components/schemas/VideoPlaylistPrivacySet'
                description:
                  description: Video playlist description
                  type: string
                  minLength: 3
                  maxLength: 1000
                videoChannelId:
                  allOf:
                    - $ref: '#/components/schemas/id'
                  description: Video channel in which the playlist will be published
              required:
                - displayName
            encoding:
              thumbnailfile:
                contentType: image/jpeg

  /api/v1/video-playlists/{playlistId}:
    get:
      summary: Get a video playlist
      tags:
        - Video Playlists
      parameters:
        - $ref: '#/components/parameters/playlistId'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VideoPlaylist'
    put:
      summary: Update a video playlist
      description: 'If the video playlist is set as public, the playlist must have a assigned channel.'
      security:
        - OAuth2: []
      tags:
        - Video Playlists
      responses:
        '204':
          description: successful operation
      parameters:
        - $ref: '#/components/parameters/playlistId'
      requestBody:
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                displayName:
                  description: Video playlist display name
                  type: string
                  minLength: 1
                  maxLength: 120
                thumbnailfile:
                  description: Video playlist thumbnail file
                  type: string
                  format: binary
                privacy:
                  $ref: '#/components/schemas/VideoPlaylistPrivacySet'
                description:
                  description: Video playlist description
                  type: string
                videoChannelId:
                  allOf:
                    - $ref: '#/components/schemas/id'
                  description: Video channel in which the playlist will be published
            encoding:
              thumbnailfile:
                contentType: image/jpeg
    delete:
      summary: Delete a video playlist
      security:
        - OAuth2: []
      tags:
        - Video Playlists
      parameters:
        - $ref: '#/components/parameters/playlistId'
      responses:
        '204':
          description: successful operation

  /api/v1/video-playlists/{playlistId}/videos:
    get:
      summary: 'List videos of a playlist'
      operationId: getVideoPlaylistVideos
      tags:
        - Videos
        - Video Playlists
      parameters:
        - $ref: '#/components/parameters/playlistId'
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                properties:
                  total:
                    type: integer
                    example: 1
                  data:
                    type: array
                    maxItems: 100
                    items:

                      type: object
                      properties:
                        id:
                          description: Playlist element id
                          allOf:
                            - $ref: '#/components/schemas/id'
                        position:
                          type: integer
                          example: 2
                        startTimestamp:
                          type: integer
                          nullable: true
                          example: 10
                          format: seconds
                        stopTimestamp:
                          type: integer
                          nullable: true
                          example: 41
                          format: seconds
                        video:
                          $ref: '#/components/schemas/Video'
    post:
      summary: Add a video in a playlist
      operationId: addVideoPlaylistVideo
      security:
        - OAuth2: []
      tags:
        - Videos
        - Video Playlists
      parameters:
        - $ref: '#/components/parameters/playlistId'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  videoPlaylistElement:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 2
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                videoId:
                  oneOf:
                    - $ref: '#/components/schemas/Video/properties/uuid'
                    - $ref: '#/components/schemas/Video/properties/id'
                  description: Video to add in the playlist
                startTimestamp:
                  type: integer
                  format: seconds
                  description: Start the video at this specific timestamp
                stopTimestamp:
                  type: integer
                  format: seconds
                  description: Stop the video at this specific timestamp
              required:
                - videoId

  /api/v1/video-playlists/{playlistId}/videos/reorder:
    post:
      summary: Reorder playlist elements
      operationId: reorderVideoPlaylist
      security:
        - OAuth2: []
      tags:
        - Video Playlists
      parameters:
        - $ref: '#/components/parameters/playlistId'
      responses:
        '204':
          description: successful operation
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                startPosition:
                  type: integer
                  description: 'Start position of the element to reorder'
                  minimum: 1
                insertAfterPosition:
                  type: integer
                  description: 'New position for the block to reorder, to add the block before the first element'
                  minimum: 0
                reorderLength:
                  type: integer
                  description: 'How many element from `startPosition` to reorder'
                  minimum: 1
              required:
                - startPosition
                - insertAfterPosition

  /api/v1/video-playlists/{playlistId}/videos/{playlistElementId}:
    put:
      summary: Update a playlist element
      operationId: putVideoPlaylistVideo
      security:
        - OAuth2: []
      tags:
        - Video Playlists
      parameters:
        - $ref: '#/components/parameters/playlistId'
        - $ref: '#/components/parameters/playlistElementId'
      responses:
        '204':
          description: successful operation
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                startTimestamp:
                  type: integer
                  format: seconds
                  description: Start the video at this specific timestamp
                stopTimestamp:
                  type: integer
                  format: seconds
                  description: Stop the video at this specific timestamp
    delete:
      summary: Delete an element from a playlist
      operationId: delVideoPlaylistVideo
      security:
        - OAuth2: []
      tags:
        - Video Playlists
      parameters:
        - $ref: '#/components/parameters/playlistId'
        - $ref: '#/components/parameters/playlistElementId'
      responses:
        '204':
          description: successful operation

  '/api/v1/users/me/video-playlists/videos-exist':
    get:
      summary: Check video exists in my playlists
      security:
        - OAuth2: []
      tags:
        - Video Playlists
      parameters:
        - name: videoIds
          in: query
          required: true
          description: The video ids to check
          schema:
            type: array
            items:
              $ref: '#/components/schemas/Video/properties/id'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  videoId:
                    type: array
                    items:
                      type: object
                      properties:
                        playlistElementId:
                          type: integer
                        playlistId:
                          type: integer
                        startTimestamp:
                          type: integer
                          format: seconds
                          nullable: true
                        stopTimestamp:
                          type: integer
                          format: seconds
                          nullable: true

  '/api/v1/accounts/{name}/video-playlists':
    get:
      summary: List playlists of an account
      tags:
        - Video Playlists
        - Accounts
      parameters:
        - $ref: '#/components/parameters/name'
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/sort'
        - $ref: '#/components/parameters/search'
        - $ref: '#/components/parameters/videoPlaylistType'
        - $ref: '#/components/parameters/includeCollaborations'
        - name: channelNameOneOf
          in: query
          required: false
          description: "**PeerTube >= 8.0** Filter on playlists that are published on a channel with one of these names"
          schema:
            oneOf:
            - type: string
            - type: array
              items:
                type: string
          style: form
          explode: true
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  total:
                    type: integer
                    example: 1
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/VideoPlaylist'

  '/api/v1/accounts/{name}/video-channels':
    get:
      summary: List video channels of an account
      tags:
        - Video Channels
        - Accounts
      parameters:
        - $ref: '#/components/parameters/name'
        - name: withStats
          in: query
          description: include view statistics time series and total views (only if authenticated as the account user)
          schema:
            type: boolean
        - name: statsDays
          in: query
          description: >
            number of days of view statistics to include in `viewsPerDay` when `withStats` is true
            (only if authenticated as the account user).
            `0` means all time (since the channel's earliest recorded stat).
            `viewsPerDay` always spans the whole requested range so channels can be compared to each other.
            Its bucket size is reported in `viewsGroupInterval`: it is derived from the requested range,
            narrowed to the channel history so that a young channel on a long range is not aggregated
            into a single coarse bucket.
            `totalViews` is unaffected by this parameter and always reports lifetime views.
          schema:
            type: integer
            enum: [30, 90, 365, 0]
            default: 30
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/search'
        - $ref: '#/components/parameters/sort'
        - $ref: '#/components/parameters/includeCollaborations'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VideoChannelList'

  '/api/v1/accounts/{name}/video-channel-syncs':
    get:
      summary: List the synchronizations of video channels of an account
      tags:
        - Video Channels
        - Channels Sync
        - Accounts
      parameters:
        - $ref: '#/components/parameters/name'
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/sort'
        - $ref: '#/components/parameters/includeCollaborations'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VideoChannelSyncList'

  '/api/v1/accounts/{name}/ratings':
    get:
      summary: List ratings of an account
      security:
        - OAuth2: []
      tags:
        - Accounts
      parameters:
        - $ref: '#/components/parameters/name'
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/sort'
        - name: rating
          in: query
          required: false
          description: Optionally filter which ratings to retrieve
          schema:
            type: string
            enum:
              - like
              - dislike
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/VideoRating'

  '/api/v1/videos/{id}/comment-threads':
    get:
      summary: List threads of a video
      tags:
        - Video Comments
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/commentsSort'
        - $ref: '#/components/parameters/videoPasswordHeader'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CommentThreadResponse'
    post:
      summary: Create a thread
      security:
        - OAuth2: []
      tags:
        - Video Comments
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CommentThreadPostResponse'
        '404':
          description: video does not exist
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                text:
                  allOf:
                    - $ref: '#/components/schemas/VideoComment/properties/text'
                  format: markdown
                  maxLength: 10000
              required:
                - text

  '/api/v1/videos/{id}/comment-threads/{threadId}':
    get:
      summary: Get a thread
      description: >
        Since PeerTube 8.3 the returned tree is truncated: only the first replies of each comment are included, and only
        down to `maxDepth` nesting levels. Use `GET /api/v1/videos/{id}/comments/{commentId}/replies` to fetch the
        replies that are missing, comparing `children` and `totalChildren` of each node of the tree.
      tags:
        - Video Comments
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
        - $ref: '#/components/parameters/threadId'
        - $ref: '#/components/parameters/commentMaxDepth'
        - $ref: '#/components/parameters/commentRepliesPerLevel'
        - $ref: '#/components/parameters/videoPasswordHeader'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VideoCommentThreadTree'

  '/api/v1/videos/{id}/comments/{commentId}/replies':
    get:
      summary: List replies of a comment
      description: >
        **PeerTube >= 8.3** List the direct replies of a comment, each of them nested up to `maxDepth` levels. Used to unfold the parts of a
        thread that `GET /api/v1/videos/{id}/comment-threads/{threadId}` truncated.
      tags:
        - Video Comments
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
        - $ref: '#/components/parameters/commentId'
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/commentRepliesSort'
        - $ref: '#/components/parameters/commentMaxDepth'
        - $ref: '#/components/parameters/commentRepliesPerLevel'
        - $ref: '#/components/parameters/videoPasswordHeader'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  total:
                    type: integer
                    example: 13
                    description: Total number of direct replies of the comment
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/VideoCommentThreadTree'

  '/api/v1/videos/comments':
    get:
      summary: List instance comments
      security:
        - OAuth2:
          - admin
          - moderator
      tags:
        - Video Comments
      parameters:
        - $ref: '#/components/parameters/search'
        - $ref: '#/components/parameters/searchAccountForComments'
        - $ref: '#/components/parameters/searchVideoForComments'
        - $ref: '#/components/parameters/videoId'
        - $ref: '#/components/parameters/videoChannelId'
        - $ref: '#/components/parameters/autoTagOneOfComment'
        - $ref: '#/components/parameters/isLocal'
        - $ref: '#/components/parameters/onLocalVideo'
        - $ref: '#/components/parameters/includeMuted'

      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  total:
                    type: integer
                    example: 1
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/VideoCommentForOwnerOrAdmin'

  '/api/v1/videos/{id}/comments/{commentId}':
    post:
      summary: Reply to a thread of a video
      security:
        - OAuth2: []
      tags:
        - Video Comments
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
        - $ref: '#/components/parameters/commentId'
        - $ref: '#/components/parameters/videoPasswordHeader'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CommentThreadPostResponse'
        '404':
          description: thread or video does not exist
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                text:
                  allOf:
                    - $ref: '#/components/schemas/VideoComment/properties/text'
                  format: markdown
                  maxLength: 10000
              required:
                - text
    delete:
      summary: Delete a comment or a reply
      security:
        - OAuth2: []
      tags:
        - Video Comments
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
        - $ref: '#/components/parameters/commentId'
      responses:
        '204':
          description: successful operation
        '403':
          description: cannot remove comment of another user
        '404':
          description: comment or video does not exist
        '409':
          description: comment is already deleted

  '/api/v1/videos/{id}/comments/{commentId}/approve':
    post:
      summary: Approve a comment
      description: "**PeerTube >= 6.2** Approve a comment that requires a review"
      security:
        - OAuth2: []
      tags:
        - Video Comments
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
        - $ref: '#/components/parameters/commentId'
      responses:
        '204':
          description: successful operation

  '/api/v1/videos/{id}/rate':
    put:
      summary: Like/dislike a video
      security:
        - OAuth2: []
      tags:
        - Video Rates
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
        - $ref: '#/components/parameters/videoPasswordHeader'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                rating:
                  type: string
                  enum:
                    - like
                    - dislike
              required:
                - rating
      responses:
        '204':
          description: successful operation
        '404':
          description: video does not exist

  '/api/v1/videos/{id}/hls':
    delete:
      summary: Delete video HLS files
      security:
        - OAuth2:
          - admin
      tags:
        - Video Files
      operationId: delVideoHLS
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
      responses:
        '204':
          description: successful operation
        '404':
          description: video does not exist
  '/api/v1/videos/{id}/web-videos':
    delete:
      summary: Delete video Web Video files
      description: "**PeerTube >= 6.0**"
      security:
        - OAuth2:
          - admin
      tags:
        - Video Files
      operationId: delVideoWebVideos
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
      responses:
        '204':
          description: successful operation
        '404':
          description: video does not exist

  '/api/v1/videos/{id}/transcoding':
    post:
      summary: Create a transcoding job
      security:
        - OAuth2:
          - admin
      tags:
        - Video Transcoding
      operationId: createVideoTranscoding
      parameters:
        - $ref: '#/components/parameters/idOrUUID'
      requestBody:
          content:
            application/json:
              schema:
                type: object
                properties:
                  transcodingType:
                    type: string
                    enum:
                      - hls
                      - web-video
                  forceTranscoding:
                    type: boolean
                    default: false
                    description: If the video is stuck in transcoding state, do it anyway
                required:
                  - transcodingType
      responses:
        '204':
          description: successful operation
        '404':
          description: video does not exist

  /api/v1/search/videos:
    get:
      tags:
        - Search
        - Video
      summary: Search videos
      operationId: searchVideos
      parameters:
        - name: search
          in: query
          required: true
          allowEmptyValue: false
          description: >
            String to search. If the user can make a remote URI search, and the string is an URI then the
            PeerTube instance will fetch the remote object and add it to its database. Then,
            you can use the REST API to fetch the complete video information and interact with it.
          schema:
            type: string
        - $ref: '#/components/parameters/uuids'
        - $ref: '#/components/parameters/searchTarget'
        # Common video filter parameters
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/skipCount'
        - $ref: '#/components/parameters/videosSort'
        - $ref: '#/components/parameters/nsfw'
        - $ref: '#/components/parameters/nsfwFlagsIncluded'
        - $ref: '#/components/parameters/nsfwFlagsExcluded'
        - $ref: '#/components/parameters/aiUsageOneOf'
        - $ref: '#/components/parameters/isLive'
        - $ref: '#/components/parameters/includeScheduledLive'
        - $ref: '#/components/parameters/categoryOneOf'
        - $ref: '#/components/parameters/licenceOneOf'
        - $ref: '#/components/parameters/languageOneOf'
        - $ref: '#/components/parameters/tagsOneOf'
        - $ref: '#/components/parameters/tagsAllOf'
        - $ref: '#/components/parameters/isLocal'
        - $ref: '#/components/parameters/include'
        - $ref: '#/components/parameters/hasHLSFiles'
        - $ref: '#/components/parameters/hasWebVideoFiles'
        - $ref: '#/components/parameters/host'
        - $ref: '#/components/parameters/autoTagOneOfVideo'
        - $ref: '#/components/parameters/stateOneOfVideo'
        - $ref: '#/components/parameters/privacyOneOf'
        - $ref: '#/components/parameters/excludeAlreadyWatched'
        - name: startDate
          in: query
          description: Get videos that are published after this date
          schema:
            type: string
            format: date-time
        - name: endDate
          in: query
          description: Get videos that are published before this date
          schema:
            type: string
            format: date-time
        - name: originallyPublishedStartDate
          in: query
          description: Get videos that are originally published after this date
          schema:
            type: string
            format: date-time
        - name: originallyPublishedEndDate
          in: query
          description: Get videos that are originally published before this date
          schema:
            type: string
            format: date-time
        - name: durationMin
          in: query
          description: Get videos that have this minimum duration
          schema:
            type: integer
        - name: durationMax
          in: query
          description: Get videos that have this maximum duration
          schema:
            type: integer
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VideoListResponse'
        '500':
          description: search index unavailable

  /api/v1/search/video-channels:
    get:
      tags:
        - Search
        - Video Channels
      summary: Search channels
      operationId: searchChannels
      parameters:
        - name: search
          in: query
          required: true
          description: >
            String to search. If the user can make a remote URI search, and the string is an URI then the
            PeerTube instance will fetch the remote object and add it to its database. Then,
            you can use the REST API to fetch the complete channel information and interact with it.
          schema:
            type: string
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/searchTarget'
        - $ref: '#/components/parameters/sort'
        - $ref: '#/components/parameters/host'
        - $ref: '#/components/parameters/handles'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VideoChannelList'
        '500':
          description: search index unavailable

  /api/v1/search/video-playlists:
    get:
      tags:
        - Search
        - Video Playlists
      summary: Search playlists
      operationId: searchPlaylists
      parameters:
        - name: search
          in: query
          required: true
          description: >
            String to search. If the user can make a remote URI search, and the string is an URI then the
            PeerTube instance will fetch the remote object and add it to its database. Then,
            you can use the REST API to fetch the complete playlist information and interact with it.
          schema:
            type: string
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/searchTarget'
        - $ref: '#/components/parameters/sort'
        - $ref: '#/components/parameters/host'
        - $ref: '#/components/parameters/uuids'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  total:
                    type: integer
                    example: 1
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/VideoPlaylist'
        '500':
          description: search index unavailable

  /api/v1/blocklist/status:
    get:
      tags:
        - Account Blocklist
        - Server Blocklist
      summary: Get block status of accounts/hosts
      parameters:
        -
          name: 'accounts'
          in: query
          description: 'Check if these accounts are blocked'
          example: [ 'goofy@example.com', 'donald@example.com' ]
          schema:
            type: array
            items:
              type: string
        -
          name: 'hosts'
          in: query
          description: 'Check if these hosts are blocked'
          example: [ 'example.com' ]
          schema:
            type: array
            items:
              type: string
      responses:
        '200':
          description: successful operation
          content:
            'application/json':
              schema:
                $ref: '#/components/schemas/BlockStatus'

  /api/v1/users/me/blocklist/accounts:
    get:
      summary: List accounts blocked by my account
      description: Get the list of accounts that the authenticated user has blocked
      operationId: getMyBlockedAccounts
      security:
        - OAuth2:
          - user
      tags:
        - Account Blocklist
      parameters:
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/sort'
        - name: search
          in: query
          required: false
          description: Search query string
          schema:
            type: string
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  total:
                    type: integer
                    example: 1
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/AccountBlock'
        '401':
          description: authentication required
    post:
      summary: Block an account by my account
      description: Add an account to the authenticated user's blocklist
      operationId: blockAccount
      security:
        - OAuth2:
          - user
      tags:
        - Account Blocklist
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                accountName:
                  type: string
                  description: "Account name to block (format: name@host)"
                  example: 'user@example.com'
              required:
                - accountName
      responses:
        '204':
          description: successful operation - account blocked
        '400':
          description: invalid account name
        '401':
          description: authentication required
        '404':
          description: account not found

  /api/v1/users/me/blocklist/accounts/{accountName}:
    delete:
      summary: Unblock an account by my account
      description: Remove an account from the authenticated user's blocklist
      operationId: unblockAccount
      security:
        - OAuth2:
          - user
      tags:
        - Account Blocklist
      parameters:
        - name: accountName
          in: path
          required: true
          description: "Account name to unblock (format: name@host)"
          schema:
            type: string
            example: 'user@example.com'
      responses:
        '204':
          description: successful operation - account unblocked
        '400':
          description: invalid account name
        '401':
          description: authentication required
        '404':
          description: account block not found

  /api/v1/users/me/blocklist/servers:
    get:
      summary: List servers blocked by my account
      description: Get the list of servers that the authenticated user has blocked
      operationId: getMyBlockedServers
      security:
        - OAuth2:
          - user
      tags:
        - Account Blocklist
      parameters:
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/sort'
        - name: search
          in: query
          required: false
          description: Search query string
          schema:
            type: string
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  total:
                    type: integer
                    example: 1
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/ServerBlock'
        '401':
          description: authentication required
    post:
      summary: Block a server by my account
      description: Add a server to the authenticated user's blocklist
      operationId: blockServer
      security:
        - OAuth2:
          - user
      tags:
        - Account Blocklist
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                host:
                  type: string
                  description: Server host to block
                  example: 'example.com'
              required:
                - host
      responses:
        '204':
          description: successful operation - server blocked
        '400':
          description: invalid server host
        '401':
          description: authentication required
        '404':
          description: server not found

  /api/v1/users/me/blocklist/servers/{host}:
    delete:
      summary: Unblock a server by my account
      description: Remove a server from the authenticated user's blocklist
      operationId: unblockServer
      security:
        - OAuth2:
          - user
      tags:
        - Account Blocklist
      parameters:
        - name: host
          in: path
          required: true
          description: Server host to unblock
          schema:
            type: string
            example: 'example.com'
      responses:
        '204':
          description: successful operation - server unblocked
        '400':
          description: invalid server host
        '401':
          description: authentication required
        '404':
          description: server block not found

  /api/v1/server/blocklist/accounts:
    get:
      tags:
        - Server Blocklist
      summary: List blocked accounts by server
      security:
        - OAuth2:
          - admin
      parameters:
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/sort'
        -
          name: subscriptionName
          in: query
          required: false
          schema:
            type: string
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  total:
                    type: integer
                    example: 1
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/AccountBlock'
    post:
      tags:
        - Server Blocklist
      summary: Block an account by server
      security:
        - OAuth2:
          - admin
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                accountName:
                  type: string
                  example: chocobozzz@example.org
                  description: account to block, in the form `username@domain`
              required:
                - accountName
      responses:
        '200':
          description: successful operation
        '409':
          description: self-blocking forbidden

  '/api/v1/server/blocklist/accounts/{accountName}':
    delete:
      tags:
        - Server Blocklist
      summary: Unblock an account by server
      security:
        - OAuth2:
          - admin
      parameters:
        - name: accountName
          in: path
          required: true
          description: account to unblock, in the form `username@domain`
          schema:
            type: string
      responses:
        '201':
          description: successful operation
        '404':
          description: account or account block does not exist

  /api/v1/server/blocklist/servers:
    get:
      tags:
        - Server Blocklist
      summary: List blocked servers by server
      security:
        - OAuth2:
          - admin
      parameters:
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/sort'
        -
          name: subscriptionName
          in: query
          required: false
          schema:
            type: string
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  total:
                    type: integer
                    example: 1
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/ServerBlock'
    post:
      tags:
        - Server Blocklist
      summary: Block a server by server
      security:
        - OAuth2:
          - admin
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                host:
                  type: string
                  format: hostname
                  description: server domain to block
              required:
                - host
      responses:
        '204':
          description: successful operation
        '409':
          description: self-blocking forbidden

  '/api/v1/server/blocklist/servers/{host}':
    delete:
      tags:
        - Server Blocklist
      summary: Unblock a server by server
      security:
        - OAuth2:
          - admin
      parameters:
        - name: host
          in: path
          required: true
          description: server domain to unblock
          schema:
            type: string
            format: hostname
      responses:
        '204':
          description: successful operation
        '404':
          description: server block does not exist

  /api/v1/server/blocklist/subscriptions:
    get:
      tags:
        - Server Blocklist
      summary: List server blocklist subscriptions
      security:
        - OAuth2:
          - admin
      parameters:
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/sort'
        - $ref: '#/components/parameters/search'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  total:
                    type: integer
                    example: 1
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/BlocklistSubscription'
    post:
      tags:
        - Server Blocklist
      summary: Add a server blocklist subscription
      security:
        - OAuth2:
          - admin
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                url:
                  type: string
                  format: url
              required:
                - url
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BlocklistSubscription'
        '409':
          description: subscription already exists

  '/api/v1/server/blocklist/subscriptions/{id}':
    delete:
      tags:
        - Server Blocklist
      summary: Delete a server blocklist subscription
      security:
        - OAuth2:
          - admin
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        '204':
          description: successful operation
        '404':
          description: subscription does not exist

  /api/v1/server/blocklist/public-log:
    get:
      tags:
        - Server Blocklist
      summary: List publicly shared server blocklist log entries
      parameters:
        - name: startDate
          in: query
          required: true
          schema:
            type: string
            format: date-time
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AutoMuteList'
        '403':
          description: public log is disabled

  /api/v1/server/redundancy/{host}:
    put:
      tags:
        - Instance Redundancy
      summary: Update a server redundancy policy
      security:
        - OAuth2:
          - admin
      parameters:
        - name: host
          in: path
          required: true
          description: server domain to mirror
          schema:
            type: string
            format: hostname
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                redundancyAllowed:
                  type: boolean
                  description: allow mirroring of the host's local videos
              required:
                - redundancyAllowed
      responses:
        '204':
          description: successful operation
        '404':
          description: server is not already known

  /api/v1/server/redundancy/videos:
    get:
      tags:
        - Video Mirroring
      summary: List videos being mirrored
      operationId: getMirroredVideos
      security:
        - OAuth2:
          - admin
      parameters:
        - name: target
          in: query
          required: true
          description: direction of the mirror
          schema:
            type: string
            enum:
              - my-videos
              - remote-videos
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/videoRedundanciesSort'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/VideoRedundancy'
    post:
      tags:
        - Video Mirroring
      summary: Mirror a video
      operationId: putMirroredVideo
      security:
        - OAuth2:
          - admin
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                videoId:
                  $ref: '#/components/schemas/Video/properties/id'
              required:
                - videoId
      responses:
        '204':
          description: successful operation
        '400':
          description: cannot mirror a local video
        '404':
          description: video does not exist
        '409':
          description: video is already mirrored

  /api/v1/server/redundancy/videos/{redundancyId}:
    delete:
      tags:
        - Video Mirroring
      summary: Delete a mirror done on a video
      operationId: delMirroredVideo
      security:
        - OAuth2:
          - admin
      parameters:
        - name: redundancyId
          in: path
          required: true
          description: id of an existing redundancy on a video
          schema:
            type: string
      responses:
        '204':
          description: successful operation
        '404':
          description: video redundancy not found

  /api/v1/server/stats:
    get:
      tags:
        - Stats
      summary: Get instance stats
      description: Get instance public statistics. This endpoint is cached.
      operationId: getInstanceStats
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ServerStats'

  /api/v1/server/contact:
    post:
      tags:
        - Contact
      summary: Contact the instance administrators
      operationId: contactAdministrator
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                fromName:
                  type: string
                  description: Display name of the sender
                fromEmail:
                  type: string
                  format: email
                  description: Email address of the sender
                subject:
                  type: string
                  description: Subject of the message
                body:
                  type: string
                  description: Message body
              required:
                - fromName
                - fromEmail
                - body
      responses:
        '204':
          description: successful operation
        '403':
          description: a contact form was already sent recently from this IP address
        '409':
          description: contact form or SMTP is not configured on this instance

  /api/v1/server/debug:
    get:
      tags:
        - Debug
      summary: Get debug information
      description: Retrieve internal debug information for administrators.
      operationId: getDebug
      security:
        - OAuth2:
          - admin
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  ip:
                    type: string
                  activityPubMessagesWaiting:
                    type: integer
                  secondariesUp:
                    type: integer
                    description: Number of secondary processes that recently sent a heartbeat
                  processes:
                    type: array
                    description: Processes of the platform that recently sent a heartbeat, the primary first
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        role:
                          type: string
                          enum:
                            - primary
                            - secondary
                        hostname:
                          type: string
                        pid:
                          type: integer
                        version:
                          type: string
                        startedAt:
                          type: string
                          format: date-time
                          description: When the process started to serve requests
                        lastSeenAt:
                          type: string
                          format: date-time

  /api/v1/server/debug/run-command:
    post:
      tags:
        - Debug
      summary: Run a debug command
      description: Run an internal debug command as an administrator.
      operationId: runDebugCommand
      security:
        - OAuth2:
          - admin
      requestBody:
        required: true
        content:
          application/json:
            schema:
              oneOf:
                - type: object
                  properties:
                    command:
                      type: string
                      enum:
                        - remove-dandling-resumable-uploads
                        - remove-expired-user-exports
                        - process-video-stats-buffer
                        - process-video-viewers
                        - process-update-videos-scheduler
                        - process-video-channel-sync-latest
                        - process-remove-old-stats
                        - process-video-files-lifecycle
                  required:
                    - command
                - type: object
                  properties:
                    command:
                      type: string
                      enum:
                        - test-emails
                    email:
                      type: string
                      format: email
                  required:
                    - command
                    - email
      responses:
        '204':
          description: successful operation
        '400':
          description: invalid command or invalid email

  /api/v1/server/logs/client:
    post:
      tags:
        - Logs
      summary: Send client log
      operationId: sendClientLog
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SendClientLog'
      responses:
        '204':
          description: successful operation

  /api/v1/server/logs:
    get:
      tags:
        - Logs
      summary: Get instance logs
      operationId: getInstanceLogs
      security:
        - OAuth2:
          - admin
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: array
                items:
                  type: string

  /api/v1/server/audit-logs:
    get:
      tags:
        - Logs
      summary: Get instance audit logs
      description: |
        User, administration and moderation actions recorded by all the PeerTube processes of the instance.

        By default (`format=array`), returns an array of at most the 10,000 most recent entries of the requested date range, oldest first.
        `startDate` is then required and pagination parameters are ignored.

        With `format=list`, returns a paginated list.
      operationId: getInstanceAuditLogs
      security:
        - OAuth2:
          - admin
      parameters:
        - name: format
          in: query
          required: false
          schema:
            type: string
            default: array
            enum:
            - array
            - list
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - name: sort
          in: query
          required: false
          schema:
            type: string
            enum:
            - -createdAt
            - createdAt
        - name: search
          in: query
          required: false
          description: Search in usernames, IP addresses and audited entities
          schema:
            type: string
        - name: entityType
          in: query
          required: false
          schema:
            $ref: '#/components/schemas/AuditLogEntityType'
        - name: entityId
          in: query
          required: false
          schema:
            type: integer
        - name: action
          in: query
          required: false
          schema:
            $ref: '#/components/schemas/AuditLogAction'
        - name: startDate
          in: query
          required: false
          description: Required with the default `array` format
          schema:
            type: string
            format: date-time
        - name: endDate
          in: query
          required: false
          schema:
            type: string
            format: date-time
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                oneOf:
                  - type: array
                    description: Default `array` format
                    items:
                      $ref: '#/components/schemas/AuditLog'
                  - type: object
                    description: '`list` format'
                    properties:
                      total:
                        type: integer
                        example: 1
                      data:
                        type: array
                        items:
                          $ref: '#/components/schemas/AuditLog'
        '403':
          description: audit log is disabled

  /api/v1/plugins:
    get:
      tags:
        - Plugins
      summary: List plugins
      operationId: getPlugins
      security:
        - OAuth2:
          - admin
      parameters:
        - name: pluginType
          in: query
          schema:
            type: integer
        - name: uninstalled
          in: query
          schema:
            type: boolean
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/sort'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PluginResponse'

  /api/v1/plugins/available:
    get:
      tags:
        - Plugins
      summary: List available plugins
      operationId: getAvailablePlugins
      security:
        - OAuth2:
          - admin
      parameters:
        - name: search
          in: query
          schema:
            type: string
        - name: pluginType
          in: query
          schema:
            type: integer
        - name: currentPeerTubeEngine
          in: query
          schema:
            type: string
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/sort'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PluginResponse'
        '503':
          description: plugin index unavailable

  /api/v1/plugins/install:
    post:
      tags:
        - Plugins
      summary: Install a plugin
      operationId: addPlugin
      security:
        - OAuth2:
          - admin
      requestBody:
        content:
          application/json:
            schema:
              oneOf:
                - type: object
                  properties:
                    npmName:
                      type: string
                      example: peertube-plugin-auth-ldap
                    currentPassword:
                      $ref: '#/components/schemas/currentPassword'
                  required:
                    - npmName
                  additionalProperties: false
                - type: object
                  properties:
                    path:
                      type: string
                    currentPassword:
                      $ref: '#/components/schemas/currentPassword'
                  required:
                    - path
                  additionalProperties: false
      responses:
        '204':
          description: successful operation
        '400':
          description: should have either `npmName` or `path` set, or `currentPassword` is missing
        '403':
          description: invalid `currentPassword`, or password confirmation unavailable for this user
        '429':
          description: too many failed password confirmations

  /api/v1/plugins/update:
    post:
      tags:
        - Plugins
      summary: Update a plugin
      operationId: updatePlugin
      security:
        - OAuth2:
          - admin
      requestBody:
        content:
          application/json:
            schema:
              oneOf:
                - type: object
                  properties:
                    npmName:
                      type: string
                      example: peertube-plugin-auth-ldap
                    currentPassword:
                      $ref: '#/components/schemas/currentPassword'
                  required:
                    - npmName
                  additionalProperties: false
                - type: object
                  properties:
                    path:
                      type: string
                    currentPassword:
                      $ref: '#/components/schemas/currentPassword'
                  required:
                    - path
                  additionalProperties: false
      responses:
        '204':
          description: successful operation
        '400':
          description: should have either `npmName` or `path` set, or `currentPassword` is missing
        '403':
          description: invalid `currentPassword`, or password confirmation unavailable for this user
        '429':
          description: too many failed password confirmations
        '404':
          description: existing plugin not found

  /api/v1/plugins/uninstall:
    post:
      tags:
        - Plugins
      summary: Uninstall a plugin
      operationId: uninstallPlugin
      security:
        - OAuth2:
          - admin
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                npmName:
                  type: string
                  description: name of the plugin/theme in its package.json
                  example: peertube-plugin-auth-ldap
              required:
                - npmName
      responses:
        '204':
          description: successful operation
        '404':
          description: existing plugin not found

  /api/v1/plugins/{npmName}:
    get:
      tags:
        - Plugins
      summary: Get a plugin
      operationId: getPlugin
      security:
        - OAuth2:
          - admin
      parameters:
        - $ref: '#/components/parameters/npmName'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Plugin'
        '404':
          description: plugin not found

  /api/v1/plugins/{npmName}/settings:
    put:
      tags:
        - Plugins
      summary: Set a plugin's settings
      security:
        - OAuth2:
          - admin
      parameters:
        - $ref: '#/components/parameters/npmName'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                settings:
                  type: object
                  additionalProperties: true
      responses:
        '204':
          description: successful operation
        '404':
          description: plugin not found

  /api/v1/plugins/{npmName}/public-settings:
    get:
      tags:
        - Plugins
      summary: Get a plugin's public settings
      parameters:
        - $ref: '#/components/parameters/npmName'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '404':
          description: plugin not found

  /api/v1/plugins/{npmName}/registered-settings:
    get:
      tags:
        - Plugins
      summary: Get a plugin's registered settings
      security:
        - OAuth2:
          - admin
      parameters:
        - $ref: '#/components/parameters/npmName'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '404':
          description: plugin not found

  /api/v1/metrics/playback:
    post:
      summary: Create playback metrics
      description: These metrics are exposed by OpenTelemetry metrics exporter if enabled.
      tags:
        - Stats
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PlaybackMetricCreate'
      responses:
        '204':
          description: successful operation

  /api/v1/runners/registration-tokens/generate:
    post:
      summary: Generate registration token
      description: Generate a new runner registration token
      security:
        - OAuth2:
          - admin
      tags:
        - Runner Registration Token
      responses:
        '204':
          description: successful operation

  /api/v1/runners/registration-tokens/{registrationTokenId}:
    delete:
      summary: Remove registration token
      description: Remove a registration token. Runners that used this token for their registration are automatically removed.
      security:
        - OAuth2:
          - admin
      tags:
        - Runner Registration Token
      parameters:
        - $ref: '#/components/parameters/registrationTokenId'
      responses:
        '204':
          description: successful operation

  /api/v1/runners/registration-tokens:
    get:
      summary: List registration tokens
      security:
        - OAuth2:
          - admin
      tags:
        - Runner Registration Token
      parameters:
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/registrationTokenSort'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  total:
                    type: integer
                    example: 1
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/RunnerRegistrationToken'

  /api/v1/runners/register:
    post:
      summary: Register a new runner
      description: API used by PeerTube runners
      tags:
        - Runners
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                registrationToken:
                  type: string
                name:
                  type: string
                description:
                  type: string
              required:
                - registrationToken
                - name
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: integer
                    description: Runner id
                  runnerToken:
                    type: string

  /api/v1/runners/unregister:
    post:
      summary: Unregister a runner
      description: API used by PeerTube runners
      tags:
        - Runners
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                runnerToken:
                  type: string
              required:
                - runnerToken
      responses:
        '204':
          description: successful operation

  /api/v1/runners/{runnerId}:
    delete:
      summary: Delete a runner
      security:
        - OAuth2:
          - admin
      tags:
        - Runners
      parameters:
        - $ref: '#/components/parameters/runnerId'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                runnerToken:
                  type: string
              required:
                - runnerToken
      responses:
        '204':
          description: successful operation

  /api/v1/runners:
    get:
      summary: List runners
      security:
        - OAuth2:
          - admin
      tags:
        - Runners
      parameters:
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/runnerSort'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  total:
                    type: integer
                    example: 1
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Runner'


  /api/v1/runners/jobs/request:
    post:
      summary: Request a new job
      description: API used by PeerTube runners
      tags:
        - Runner Jobs
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                runnerToken:
                  type: string
                jobTypes:
                  type: array
                  description: Filter jobs depending on their types
                  items:
                    type: string
              required:
                - runnerToken
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  availableJobs:
                    type: array
                    items:
                      type: object
                      properties:
                        uuid:
                          $ref: '#/components/schemas/UUIDv4'
                        type:
                          $ref: '#/components/schemas/RunnerJobType'
                        payload:
                          $ref: '#/components/schemas/RunnerJobPayload'

  /api/v1/runners/jobs/{jobUUID}/accept:
    post:
      summary: Accept job
      description: API used by PeerTube runners
      tags:
        - Runner Jobs
      parameters:
        - $ref: '#/components/parameters/jobUUID'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                runnerToken:
                  type: string
              required:
                - runnerToken
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  job:
                    allOf:
                      - $ref: '#/components/schemas/RunnerJob'
                      - type: object
                        properties:
                          jobToken:
                            type: string

  /api/v1/runners/jobs/{jobUUID}/abort:
    post:
      summary: Abort job
      description: API used by PeerTube runners
      tags:
        - Runner Jobs
      parameters:
        - $ref: '#/components/parameters/jobUUID'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                runnerToken:
                  type: string
                jobToken:
                  type: string
                reason:
                  type: string
                  description: Why the runner aborts this job
              required:
                - runnerToken
                - jobToken
                - reason
      responses:
        '204':
          description: successful operation

  /api/v1/runners/jobs/{jobUUID}/update:
    post:
      summary: Update job
      description: API used by PeerTube runners
      tags:
        - Runner Jobs
      parameters:
        - $ref: '#/components/parameters/jobUUID'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                runnerToken:
                  type: string
                jobToken:
                  type: string
                progress:
                  type: integer
                  description: Update job progression percentage (optional)
                payload:
                  anyOf:
                    - type: object
                      description: Provide live transcoding chunks update
                      properties:
                        type:
                          type: string
                          enum:
                            - 'add-chunk'
                            - 'remove-chunk'
                        masterPlaylistFile:
                          type: string
                          format: binary
                        resolutionPlaylistFile:
                          type: string
                          format: binary
                        resolutionPlaylistFilename:
                          type: string
                        videoChunkFile:
                          type: string
                          format: binary
                        videoChunkFilename:
                          type: string
              required:
                - runnerToken
                - jobToken
      responses:
        '204':
          description: successful operation

  /api/v1/runners/jobs/{jobUUID}/error:
    post:
      summary: Post job error
      description: API used by PeerTube runners
      tags:
        - Runner Jobs
      parameters:
        - $ref: '#/components/parameters/jobUUID'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                runnerToken:
                  type: string
                jobToken:
                  type: string
                message:
                  type: string
                  description: Why the runner failed to process this job
              required:
                - runnerToken
                - jobToken
                - message
      responses:
        '204':
          description: successful operation

  /api/v1/runners/jobs/{jobUUID}/success:
    post:
      summary: Post job success
      description: API used by PeerTube runners
      tags:
        - Runner Jobs
      parameters:
        - $ref: '#/components/parameters/jobUUID'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                runnerToken:
                  type: string
                jobToken:
                  type: string
                payload:
                  anyOf:
                    - type: object
                      title: VOD web video transcoding
                      properties:
                        videoFile:
                          type: string
                          format: binary
                    - type: object
                      title: VOD HLS transcoding
                      properties:
                        videoFile:
                          type: string
                          format: binary
                        resolutionPlaylistFile:
                          type: string
                          format: binary
                    - type: object
                      title: VOD audio merge transcoding
                      properties:
                        videoFile:
                          type: string
                          format: binary
                    - type: object
                      title: Live RTMP to HLS transcoding
              required:
                - runnerToken
                - jobToken
                - payload
      responses:
        '204':
          description: successful operation

  /api/v1/runners/jobs/{jobUUID}/files/videos/{videoIdOrUUID}/max-quality/audio:
    post:
      summary: Download the max-quality audio file for a job video
      description: API used by PeerTube runners.
      tags:
        - Runner Jobs
      parameters:
        - $ref: '#/components/parameters/jobUUID'
        - $ref: '#/components/parameters/videoIdOrUUID'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                runnerToken:
                  type: string
                jobToken:
                  type: string
              required:
                - runnerToken
                - jobToken
      responses:
        '200':
          description: successful operation
          content:
            application/octet-stream:
              schema:
                type: string
                format: binary
        '403':
          description: the job is not associated with this video

  /api/v1/runners/jobs/{jobUUID}/files/videos/{videoIdOrUUID}/max-quality:
    post:
      summary: Download the max-quality video file for a job video
      description: API used by PeerTube runners.
      tags:
        - Runner Jobs
      parameters:
        - $ref: '#/components/parameters/jobUUID'
        - $ref: '#/components/parameters/videoIdOrUUID'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                runnerToken:
                  type: string
                jobToken:
                  type: string
              required:
                - runnerToken
                - jobToken
      responses:
        '200':
          description: successful operation
          content:
            application/octet-stream:
              schema:
                type: string
                format: binary
        '403':
          description: the job is not associated with this video

  /api/v1/runners/jobs/{jobUUID}/files/videos/{videoIdOrUUID}/thumbnails/max-quality:
    post:
      summary: Download the max-quality thumbnail for a job video
      description: API used by PeerTube runners.
      tags:
        - Runner Jobs
      parameters:
        - $ref: '#/components/parameters/jobUUID'
        - $ref: '#/components/parameters/videoIdOrUUID'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                runnerToken:
                  type: string
                jobToken:
                  type: string
              required:
                - runnerToken
                - jobToken
      responses:
        '200':
          description: successful operation
          content:
            application/octet-stream:
              schema:
                type: string
                format: binary
        '403':
          description: the job is not associated with this video

  /api/v1/runners/jobs/{jobUUID}/files/videos/{videoIdOrUUID}/previews/max-quality:
    post:
      summary: Download the max-quality preview for a job video
      description: API used by PeerTube runners.
      tags:
        - Runner Jobs
      parameters:
        - $ref: '#/components/parameters/jobUUID'
        - $ref: '#/components/parameters/videoIdOrUUID'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                runnerToken:
                  type: string
                jobToken:
                  type: string
              required:
                - runnerToken
                - jobToken
      responses:
        '200':
          description: successful operation
          content:
            application/octet-stream:
              schema:
                type: string
                format: binary
        '403':
          description: the job is not associated with this video

  /api/v1/runners/jobs/{jobUUID}/files/videos/{videoIdOrUUID}/studio/task-files/{filename}:
    post:
      summary: Download a video studio task file for a job video
      description: API used by PeerTube runners.
      tags:
        - Runner Jobs
      parameters:
        - $ref: '#/components/parameters/jobUUID'
        - $ref: '#/components/parameters/videoIdOrUUID'
        - name: filename
          in: path
          required: true
          description: Name of the task file to download
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                runnerToken:
                  type: string
                jobToken:
                  type: string
              required:
                - runnerToken
                - jobToken
      responses:
        '200':
          description: successful operation
          content:
            application/octet-stream:
              schema:
                type: string
                format: binary
        '400':
          description: the file is not associated with this edition task
        '403':
          description: the job is not associated with this video

  /api/v1/runners/jobs/{jobUUID}/cancel:
    post:
      summary: Cancel a job
      security:
        - OAuth2:
          - admin
      tags:
        - Runner Jobs
      parameters:
        - $ref: '#/components/parameters/jobUUID'
      responses:
        '204':
          description: successful operation

  /api/v1/runners/jobs/{jobUUID}:
    delete:
      summary: Delete a job
      description: The endpoint will first cancel the job if needed, and then remove it from the database. Children jobs will also be removed
      security:
        - OAuth2:
          - admin
      tags:
        - Runner Jobs
      parameters:
        - $ref: '#/components/parameters/jobUUID'
      responses:
        '204':
          description: successful operation

  /api/v1/runners/jobs:
    get:
      summary: List jobs
      security:
        - OAuth2:
          - admin
      tags:
        - Runner Jobs
      parameters:
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/runnerJobSort'
        - $ref: '#/components/parameters/search'
        - name: stateOneOf
          in: query
          required: false
          schema:
            type: array
            items:
              $ref: '#/components/schemas/RunnerJobState'
        - name: typeOneOf
          in: query
          required: false
          schema:
            type: array
            items:
              $ref: '#/components/schemas/RunnerJobType'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  total:
                    type: integer
                    example: 1
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/RunnerJobAdmin'

  /api/v1/automatic-tags/policies/accounts/{accountName}/comments:
    get:
      tags:
        - Automatic Tags
      summary: Get account auto tag policies on comments
      description: "**PeerTube >= 6.2**"
      security:
        - OAuth2: []
      parameters:
        - name: accountName
          in: path
          required: true
          description: account name to get auto tag policies
          schema:
            type: string
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CommentAutoTagPolicies'
    put:
      tags:
        - Automatic Tags
      summary: Update account auto tag policies on comments
      description: "**PeerTube >= 6.2**"
      security:
        - OAuth2: []
      parameters:
        - name: accountName
          in: path
          required: true
          description: account name to update auto tag policies
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                review:
                  description: 'Auto tags that automatically set the comment in review state'
                  type: array
                  items:
                    type: string
      responses:
        '204':
          description: successful operation

  /api/v1/automatic-tags/accounts/{accountName}/available:
    get:
      tags:
        - Automatic Tags
      summary: Get account available auto tags
      description: "**PeerTube >= 6.2**"
      security:
        - OAuth2: []
      parameters:
        - name: accountName
          in: path
          required: true
          description: account name to get auto tag policies
          schema:
            type: string
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AutomaticTagAvailable'
  /api/v1/automatic-tags/server/available:
    get:
      tags:
        - Automatic Tags
      summary: Get server available auto tags
      description: "**PeerTube >= 6.2**"
      security:
        - OAuth2:
          - admin
          - moderator
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AutomaticTagAvailable'

  /api/v1/automatic-tags/policies/server/videos:
    get:
      tags:
        - Automatic Tags
      summary: Get server auto tag policies for videos
      description: "**PeerTube >= 8.3**"
      security:
        - OAuth2:
          - admin
          - moderator
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VideoAutoTagPolicies'
    put:
      tags:
        - Automatic Tags
      summary: Update server auto tag policies for videos
      description: "**PeerTube >= 8.3**"
      security:
        - OAuth2:
          - admin
          - moderator
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                autoBlock:
                  description: 'Auto tags that will automatically block videos matching these tags'
                  type: array
                  items:
                    type: string
      responses:
        '204':
          description: successful operation

  /api/v1/watched-words/accounts/{accountName}/lists:
    get:
      tags:
        - Watched Words
      summary: List account watched words
      description: "**PeerTube >= 6.2**"
      security:
        - OAuth2: []
      parameters:
        - name: accountName
          in: path
          required: true
          description: account name to list watched words
          schema:
            type: string
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                properties:
                  total:
                    type: integer
                    example: 1
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/WatchedWordsLists'
    post:
      tags:
        - Watched Words
      summary: Add account watched words
      description: "**PeerTube >= 6.2**"
      security:
        - OAuth2: []
      parameters:
        - name: accountName
          in: path
          required: true
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                listName:
                  type: string
                words:
                  type: array
                  items:
                    type: string
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  watchedWordsList:
                    type: object
                    properties:
                      id:
                        type: integer

  /api/v1/watched-words/accounts/{accountName}/lists/{listId}:
    put:
      tags:
        - Watched Words
      summary: Update account watched words
      description: "**PeerTube >= 6.2**"
      security:
        - OAuth2: []
      parameters:
        - name: accountName
          in: path
          required: true
          schema:
            type: string
        - name: listId
          in: path
          required: true
          description: list of watched words to update
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                listName:
                  type: string
                words:
                  type: array
                  items:
                    type: string
      responses:
        '204':
          description: successful operation
    delete:
      tags:
        - Watched Words
      summary: Delete account watched words
      description: "**PeerTube >= 6.2**"
      security:
        - OAuth2: []
      parameters:
        - name: accountName
          in: path
          required: true
          schema:
            type: string
        - name: listId
          in: path
          required: true
          description: list of watched words to delete
          schema:
            type: string
      responses:
        '204':
          description: successful operation

  /api/v1/watched-words/server/lists:
    get:
      tags:
        - Watched Words
      summary: List server watched words
      description: "**PeerTube >= 6.2**"
      security:
        - OAuth2:
          - admin
          - moderator
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                properties:
                  total:
                    type: integer
                    example: 1
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/WatchedWordsLists'
    post:
      tags:
        - Watched Words
      summary: Add server watched words
      description: "**PeerTube >= 6.2**"
      security:
        - OAuth2:
          - admin
          - moderator
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                listName:
                  type: string
                words:
                  type: array
                  items:
                    type: string
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  watchedWordsList:
                    type: object
                    properties:
                      id:
                        type: integer

  /api/v1/watched-words/server/lists/{listId}:
    put:
      tags:
        - Watched Words
      summary: Update server watched words
      description: "**PeerTube >= 6.2**"
      security:
        - OAuth2:
          - admin
          - moderator
      parameters:
        - name: listId
          in: path
          required: true
          description: list of watched words to update
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                listName:
                  type: string
                words:
                  type: array
                  items:
                    type: string
      responses:
        '204':
          description: successful operation
    delete:
      tags:
        - Watched Words
      summary: Delete server watched words
      description: "**PeerTube >= 6.2**"
      security:
        - OAuth2:
          - admin
          - moderator
      parameters:
        - name: listId
          in: path
          required: true
          description: list of watched words to delete
          schema:
            type: string
      responses:
        '204':
          description: successful operation

  /api/v1/watched-words/accounts/{accountName}/subscriptions:
    get:
      tags:
        - Watched Words
      summary: List account watched words subscriptions
      security:
        - OAuth2: []
      parameters:
        - name: accountName
          in: path
          required: true
          description: account name to list watched words subscriptions
          schema:
            type: string
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/sort'
        - $ref: '#/components/parameters/search'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  total:
                    type: integer
                    example: 1
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/WatchedWordsSubscription'
    post:
      tags:
        - Watched Words
      summary: Add account watched words subscription
      security:
        - OAuth2: []
      parameters:
        - name: accountName
          in: path
          required: true
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                url:
                  type: string
                  format: url
              required:
                - url
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WatchedWordsSubscription'
        '400':
          description: cannot fetch or parse watched words URL
        '409':
          description: subscription already exists or watched words list with fetched name already exists

  /api/v1/watched-words/accounts/{accountName}/subscriptions/{id}:
    delete:
      tags:
        - Watched Words
      summary: Delete account watched words subscription
      security:
        - OAuth2: []
      parameters:
        - name: accountName
          in: path
          required: true
          schema:
            type: string
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        '204':
          description: successful operation
        '404':
          description: watched words subscription does not exist

  /api/v1/watched-words/server/subscriptions:
    get:
      tags:
        - Watched Words
      summary: List server watched words subscriptions
      security:
        - OAuth2:
          - admin
          - moderator
      parameters:
        - $ref: '#/components/parameters/start'
        - $ref: '#/components/parameters/count'
        - $ref: '#/components/parameters/sort'
        - $ref: '#/components/parameters/search'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  total:
                    type: integer
                    example: 1
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/WatchedWordsSubscription'
    post:
      tags:
        - Watched Words
      summary: Add server watched words subscription
      security:
        - OAuth2:
          - admin
          - moderator
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                url:
                  type: string
                  format: url
              required:
                - url
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WatchedWordsSubscription'
        '400':
          description: cannot fetch or parse watched words URL
        '409':
          description: subscription already exists or watched words list with fetched name already exists

  /api/v1/watched-words/server/subscriptions/{id}:
    delete:
      tags:
        - Watched Words
      summary: Delete server watched words subscription
      security:
        - OAuth2:
          - admin
          - moderator
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        '204':
          description: successful operation
        '404':
          description: watched words subscription does not exist

  /api/v1/client-config/update-language:
    post:
      tags:
        - Client Config
      summary: Update client language
      description: Set a cookie so that the next time the client refreshes the HTML of the web interface, PeerTube uses the selected language.
      operationId: updateClientLanguage
      deprecated: true
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                language:
                  type: string
                  nullable: true
                  description: Language code to set
                  example: 'en-US'
              required:
                - language
      responses:
        '204':
          description: successful operation

  /api/v1/client-config/update-interface-language:
    post:
      tags:
        - Client Config
      summary: Update client language
      description: Set a cookie so that the next time the client refreshes the HTML of the web interface, PeerTube uses the selected language.
      operationId: updateClientInterfaceLanguage
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                language:
                  type: string
                  nullable: true
                  description: Language code to set, or `null` to clear the preference
                  example: 'en-US'
              required:
                - language
      responses:
        '204':
          description: successful operation

  /api/v1/video-channels/{channelHandle}/collaborators:
    get:
      tags:
        - Video Channels
      summary: List channel collaborators
      description: "**PeerTube >= 8.0**"
      operationId: listVideoChannelCollaborators
      security:
        - OAuth2: []
      parameters:
        - $ref: '#/components/parameters/channelHandle'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  total:
                    type: integer
                    example: 1
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/VideoChannelCollaborator'

  /api/v1/video-channels/{channelHandle}/collaborators/invite:
    post:
      tags:
        - Video Channels
      summary: Invite a collaborator
      operationId: inviteVideoChannelCollaborator
      description: "**PeerTube >= 8.0**  Invite a local user to collaborate on the specified video channel."
      security:
        - OAuth2: []
      parameters:
        - $ref: '#/components/parameters/channelHandle'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                accountHandle:
                  type: string
                  description: Local user username to invite
      responses:
        '200':
          description: Collaborator invited
          content:
            application/json:
              schema:
                type: object
                properties:
                  collaborator:
                    $ref: '#/components/schemas/VideoChannelCollaborator'

  /api/v1/video-channels/{channelHandle}/collaborators/{collaboratorId}/accept:
    post:
      tags:
        - Video Channels
      summary: Accept a collaboration invitation
      description: "**PeerTube >= 8.0**"
      operationId: acceptVideoChannelCollaborator
      security:
        - OAuth2: []
      parameters:
        - $ref: '#/components/parameters/channelHandle'
        - $ref: '#/components/parameters/collaboratorId'
      responses:
        '204':
          description: Collaboration accepted

  /api/v1/video-channels/{channelHandle}/collaborators/{collaboratorId}/reject:
    post:
      tags:
        - Video Channels
      summary: Reject a collaboration invitation
      description: "**PeerTube >= 8.0**"
      operationId: rejectVideoChannelCollaborator
      security:
        - OAuth2: []
      parameters:
        - $ref: '#/components/parameters/channelHandle'
        - $ref: '#/components/parameters/collaboratorId'
      responses:
        '204':
          description: Collaboration rejected

  /api/v1/video-channels/{channelHandle}/collaborators/{collaboratorId}:
    delete:
      tags:
        - Video Channels
      summary: Remove a channel collaborator
      description: "**PeerTube >= 8.0** Only the channel owner or the collaborator themselves can remove a collaborator from a channel"
      operationId: removeVideoChannelCollaborator
      security:
        - OAuth2: []
      parameters:
        - $ref: '#/components/parameters/channelHandle'
        - $ref: '#/components/parameters/collaboratorId'
      responses:
        '204':
          description: successful operation

servers:
  - url: 'https://peertube2.cpy.re'
    description: Live Test Server (live data - latest nightly version)
  - url: 'https://peertube3.cpy.re'
    description: Live Test Server (live data - latest RC version)
  - url: 'https://peertube.cpy.re'
    description: Live Test Server (live data - stable version)
components:
  parameters:
    start:
      name: start
      in: query
      required: false
      description: Offset used to paginate results
      schema:
        type: integer
        minimum: 0
    count:
      name: count
      in: query
      required: false
      description: "Number of items to return"
      schema:
        type: integer
        default: 15
        maximum: 100
        minimum: 1
    sort:
      name: sort
      in: query
      required: false
      description: Sort column
      schema:
        type: string
        example: -createdAt
    search:
      name: search
      in: query
      required: false
      description: Plain text search, applied to various parts of the model depending on endpoint
      schema:
        type: string
    searchTarget:
      name: searchTarget
      in: query
      required: false
      description: >
        If the administrator enabled search index support, you can override the default search target.


        **Warning**: If you choose to make an index search, PeerTube will get results from a third party service.
        It means the instance may not yet know the objects you fetched. If you want to load video/channel information:
          * If the current user has the ability to make a remote URI search (this information is available in the config endpoint),
          then reuse the search API to make a search using the object URI so PeerTube instance fetches the remote object and fill its database.
          After that, you can use the classic REST API endpoints to fetch the complete object or interact with it
          * If the current user doesn't have the ability to make a remote URI search, then redirect the user on the origin instance or fetch
          the data from the origin instance API
      schema:
        type: string
        enum:
          - 'local'
          - 'search-index'
    mySubscriptionSort:
      name: sort
      in: query
      required: false
      schema:
        type: string
        enum:
          - -id
          - -createdAt
          - -channelUpdatedAt
    videosSort:
      name: sort
      in: query
      required: false
      schema:
        type: string
        enum:
          - name
          - -duration
          - -createdAt
          - -publishedAt
          - -views
          - -likes
          - -comments
          - -trending
          - -hot
          - -best
        description: >
          Sort videos by criteria (prefixing with `-` means `DESC` order):
            * `hot` - Adaptation of Reddit "hot" algorithm taking into account video views, likes, dislikes and comments and publication date
            * `best` - Same than `hot`, but also takes into account user video history
            * `trending` - Sort videos by recent views ("recent" is defined by the admin)
            * `views` - Sort videos using their `views` counter
            * `publishedAt` - Sort by video publication date (when it became publicly available)
    videosSearchSort:
      name: sort
      in: query
      required: false
      description: >
        Sort videos by criteria (prefixing with `-` means `DESC` order):
      schema:
        type: string
        enum:
        - name
        - -duration
        - -createdAt
        - -publishedAt
        - -views
        - -likes
        - -match
    commentsSort:
      name: sort
      in: query
      required: false
      description: Sort comments by criteria
      schema:
        type: string
        enum:
        - -createdAt
        - -totalReplies
    blacklistsSort:
      name: sort
      in: query
      required: false
      description: Sort blocklists by criteria
      schema:
        type: string
        enum:
        - -id
        - name
        - -duration
        - -views
        - -likes
        - -dislikes
        - -uuid
        - -createdAt
    usersSearch:
      name: search
      in: query
      required: false
      description: Plain text search that will match with user usernames or emails
      schema:
        type: string
    usersBlocked:
      name: blocked
      in: query
      required: false
      description: Filter results down to (un)banned users
      schema:
        type: boolean
    usersRole:
      name: role
      in: query
      required: false
      description: Filter results down to users with a specific role
      schema:
        $ref: '#/components/schemas/UserRole'
    usersSort:
      name: sort
      in: query
      required: false
      description: Sort users by criteria
      schema:
        type: string
        enum:
        - -id
        - -username
        - -createdAt
    abusesSort:
      name: sort
      in: query
      required: false
      description: Sort abuses by criteria
      schema:
        type: string
        enum:
        - -id
        - -createdAt
        - -state
    videoRedundanciesSort:
      name: sort
      in: query
      required: false
      description: Sort abuses by criteria
      schema:
        type: string
        enum:
        - name
    followersSort:
      name: sort
      in: query
      required: false
      description: Sort followers by criteria
      schema:
        type: string
        enum:
        - createdAt
    registrationTokenSort:
      name: sort
      in: query
      required: false
      description: Sort registration tokens by criteria
      schema:
        type: string
        enum:
        - createdAt
    runnerSort:
      name: sort
      in: query
      required: false
      description: Sort runners by criteria
      schema:
        type: string
        enum:
        - createdAt
    runnerJobSort:
      name: sort
      in: query
      required: false
      description: Sort runner jobs by criteria
      schema:
        type: string
        enum:
        - updatedAt
        - createdAt
        - priority
        - state
        - progress

    name:
      name: name
      in: path
      required: true
      description: The username or handle of the account
      schema:
        type: string
        example: chocobozzz | chocobozzz@example.org
    id:
      name: id
      in: path
      required: true
      description: Entity id
      schema:
        $ref: '#/components/schemas/id'
    tokenSessionId:
      name: tokenSessionId
      in: path
      required: true
      description: Token session Id
      schema:
        $ref: '#/components/schemas/id'
    userId:
      name: userId
      in: path
      required: true
      description: User id
      schema:
        $ref: '#/components/schemas/id'
    registrationId:
      name: registrationId
      in: path
      required: true
      description: Registration ID
      schema:
        $ref: '#/components/schemas/id'
    idOrUUID:
      name: id
      in: path
      required: true
      description: The object id, uuid or short uuid
      schema:
        oneOf:
          - $ref: '#/components/schemas/id'
          - $ref: '#/components/schemas/UUIDv4'
          - $ref: '#/components/schemas/shortUUID'
    playlistId:
      name: playlistId
      in: path
      required: true
      description: Playlist id
      schema:
        $ref: '#/components/schemas/VideoPlaylist/properties/id'
    videoIdOrUUID:
      name: videoIdOrUUID
      in: path
      required: true
      description: Video id or UUID
      schema:
        oneOf:
          - $ref: '#/components/schemas/id'
          - $ref: '#/components/schemas/UUIDv4'
          - $ref: '#/components/schemas/shortUUID'
    playlistElementId:
      name: playlistElementId
      in: path
      required: true
      description: Playlist element id
      schema:
        $ref: '#/components/schemas/id'
    abuseId:
      name: abuseId
      in: path
      required: true
      description: Abuse id
      schema:
        $ref: '#/components/schemas/Abuse/properties/id'
    abuseMessageId:
      name: abuseMessageId
      in: path
      required: true
      description: Abuse message id
      schema:
        $ref: '#/components/schemas/AbuseMessage/properties/id'
    captionLanguage:
      name: captionLanguage
      in: path
      required: true
      description: The caption language
      schema:
        $ref: '#/components/schemas/VideoLanguageSet'
    channelHandle:
      name: channelHandle
      in: path
      required: true
      description: The video channel handle
      schema:
        type: string
        example: my_username | my_username@example.com
    channelSyncId:
      name: channelSyncId
      in: path
      required: true
      description: Channel Sync id
      schema:
        $ref: '#/components/schemas/Abuse/properties/id'
    subscriptionHandle:
      name: subscriptionHandle
      in: path
      required: true
      description: The subscription handle
      schema:
        type: string
        example: my_username | my_username@example.com
    threadId:
      name: threadId
      in: path
      required: true
      description: The thread id (root comment id)
      schema:
        type: integer
    commentId:
      name: commentId
      in: path
      required: true
      description: The comment id
      schema:
        $ref: '#/components/schemas/VideoComment/properties/id'
    commentMaxDepth:
      name: maxDepth
      in: query
      required: false
      description: >
        Number of nesting levels to include below the requested comment.

        Bounded by `repliesPerLevel` and `count`, see the note on `repliesPerLevel`
      schema:
        type: integer
        minimum: 1
        maximum: 10
        default: 5
    commentRepliesPerLevel:
      name: repliesPerLevel
      in: query
      required: false
      description: >
        Number of direct replies to include for each comment of the tree. Does not apply to the first level of
        `GET /api/v1/videos/{id}/comments/{commentId}/replies`, which is paginated using `start` and `count`.

        A tree can make the server walk through
        `count * (repliesPerLevel ^ maxDepth - 1) / (repliesPerLevel - 1)` comments, which grows exponentially.
        Combinations above 2000000 are rejected
        A deep tree has to be narrow and a wide tree has to be shallow.
      schema:
        type: integer
        minimum: 1
        maximum: 30
        default: 10
    commentRepliesSort:
      name: sort
      in: query
      required: false
      description: >
        Sort the direct replies of the comment. Deeper levels of the tree are always sorted the same way.

        Defaults to `createdAt` so the replies are appended to the thread tree in the order it was built
      schema:
        type: string
        default: createdAt
        enum:
        - createdAt
        - -createdAt
    isLive:
      name: isLive
      in: query
      required: false
      description: whether or not the video is a live
      schema:
        type: boolean
    includeScheduledLive:
      name: includeScheduledLive
      in: query
      required: false
      description: whether or not include live that are scheduled for later
      schema:
        type: boolean
    categoryOneOf:
      name: categoryOneOf
      in: query
      required: false
      description: category id of the video (see [/videos/categories](#operation/getCategories))
      schema:
        oneOf:
        - $ref: '#/components/schemas/VideoCategorySet'
        - type: array
          items:
            $ref: '#/components/schemas/VideoCategorySet'
      style: form
      explode: true
    tagsOneOf:
      name: tagsOneOf
      in: query
      required: false
      description: tag(s) of the video
      schema:
        oneOf:
        - type: string
        - type: array
          maxItems: 5
          items:
            type: string
      style: form
      explode: true
    tagsAllOf:
      name: tagsAllOf
      in: query
      required: false
      description: tag(s) of the video, where all should be present in the video
      schema:
        oneOf:
        - type: string
        - type: array
          items:
            type: string
      style: form
      explode: true
    languageOneOf:
      name: languageOneOf
      in: query
      required: false
      description: language id of the video (see [/videos/languages](#operation/getLanguages)). Use `_unknown` to filter on videos that don't have a video language
      schema:
        oneOf:
        - $ref: '#/components/schemas/VideoLanguageSet'
        - type: array
          items:
            $ref: '#/components/schemas/VideoLanguageSet'
      style: form
      explode: true
    autoTagOneOfVideo:
      name: autoTagOneOf
      in: query
      required: false
      description: "**PeerTube >= 6.2** **Admins and moderators only** filter on videos that contain one of these automatic tags"
      schema:
        oneOf:
        - type: string
        - type: array
          items:
            type: string
      style: form
      explode: true
    stateOneOfVideo:
      name: stateOneOf
      in: query
      required: false
      description: "**PeerTube >= 8.2** **Admins and moderators only** filter on videos that have one of these states"
      schema:
        oneOf:
        - $ref: '#/components/schemas/VideoStateConstant/properties/id'
        - type: array
          items:
            $ref: '#/components/schemas/VideoStateConstant/properties/id'
      style: form
      explode: true
    channelNameOneOf:
      name: channelNameOneOf
      in: query
      required: false
      description: "**PeerTube >= 7.2** Filter on videos that are published by a channel with one of these names"
      schema:
        oneOf:
        - type: string
        - type: array
          items:
            type: string
      style: form
      explode: true
    autoTagOneOfComment:
      name: autoTagOneOf
      in: query
      required: false
      description: "**PeerTube >= 6.2** filter on comments that contain one of these automatic tags"
      schema:
        oneOf:
        - type: string
        - type: array
          items:
            type: string
      style: form
      explode: true
    isHeldForReview:
      name: isHeldForReview
      in: query
      required: false
      description: only display comments that are held for review
      schema:
        type: boolean
    licenceOneOf:
      name: licenceOneOf
      in: query
      required: false
      description: licence id of the video (see [/videos/licences](#operation/getLicences))
      schema:
        oneOf:
        - $ref: '#/components/schemas/VideoLicenceSet'
        - type: array
          items:
            $ref: '#/components/schemas/VideoLicenceSet'
      style: form
      explode: true
    skipCount:
      name: skipCount
      in: query
      required: false
      description: if you don't need the `total` in the response
      schema:
        type: string
        enum:
          - 'true'
          - 'false'
        default: 'false'
    nsfw:
      name: nsfw
      in: query
      required: false
      description: whether to include nsfw videos, if any
      schema:
        type: string
        enum:
        - 'true'
        - 'false'
    nsfwFlagsIncluded:
      name: nsfwFlagsIncluded
      in: query
      required: false
      schema:
        $ref: '#/components/schemas/NSFWFlag'
    nsfwFlagsExcluded:
      name: nsfwFlagsExcluded
      in: query
      required: false
      schema:
        $ref: '#/components/schemas/NSFWFlag'
    aiUsageOneOf:
      name: aiUsageOneOf
      in: query
      required: false
      description: |
        **PeerTube >= 9.0** Only list videos with one of these AI usages, declared by video creators.
        If not provided, the preference of the authenticated user (`aiUsagesHidden`) is used
      schema:
        oneOf:
        - $ref: '#/components/schemas/VideoAIUsageSet'
        - type: array
          items:
            $ref: '#/components/schemas/VideoAIUsageSet'
      style: form
      explode: true
    isLocal:
      name: isLocal
      in: query
      required: false
      schema:
        type: boolean
      description: '**PeerTube >= 4.0** Display only local or remote objects'
    hasHLSFiles:
      name: hasHLSFiles
      in: query
      required: false
      schema:
        type: boolean
      description: '**PeerTube >= 4.0** Display only videos that have HLS files'
    hasWebVideoFiles:
      name: hasWebVideoFiles
      in: query
      required: false
      schema:
        type: boolean
      description: '**PeerTube >= 6.0** Display only videos that have Web Video files'
    privacyOneOf:
      name: privacyOneOf
      in: query
      required: false
      schema:
        $ref: '#/components/schemas/VideoPrivacySet'
      description: '**PeerTube >= 4.0** Display only videos in this specific privacy/privacies'
    excludeAlreadyWatched:
      name: excludeAlreadyWatched
      in: query
      description: Whether or not to exclude videos that are in the user's video history
      schema:
        type: boolean
    uuids:
      name: uuids
      in: query
      required: false
      schema:
        items:
          type: string
      description: 'Find elements with specific UUIDs'
    host:
      name: host
      in: query
      required: false
      schema:
          type: string
      description: 'Find elements owned by this host'
    handles:
      name: handles
      in: query
      required: false
      schema:
        items:
          type: string
      description: 'Find elements with these handles'
    include:
      name: include
      in: query
      required: false
      schema:
        type: integer
        enum:
        - 0
        - 1
        - 2
        - 4
        - 8
        - 16
        - 32
      description: >
        **Only administrators and moderators can use this parameter**


        Include additional videos in results (can be combined using bitwise or operator)

        - `0` NONE

        - `1` NOT_PUBLISHED_STATE

        - `2` BLACKLISTED

        - `4` BLOCKED_OWNER

        - `8` FILES

        - `16` CAPTIONS

        - `32` VIDEO SOURCE
    subscriptionsUris:
      name: uris
      in: query
      required: true
      description: list of uris to check if each is part of the user subscriptions
      schema:
        type: array
        items:
          type: string
          format: uri
    npmName:
      name: npmName
      in: path
      required: true
      description: name of the plugin/theme on npmjs.com or in its package.json
      schema:
        type: string
        example: peertube-plugin-auth-ldap
    jobType:
      name: jobType
      in: query
      required: false
      description: job type
      schema:
        $ref: '#/components/schemas/JobType'
    followState:
      name: state
      in: query
      schema:
        type: string
        enum:
          - pending
          - accepted
    actorType:
      name: actorType
      in: query
      schema:
        type: string
        enum:
          - Person
          - Application
          - Group
          - Service
          - Organization
    staticFilename:
      name: filename
      in: path
      required: true
      description: Filename
      schema:
        type: string
    videoFileToken:
      name: videoFileToken
      in: query
      required: false
      description: Video file token [generated](#operation/requestVideoToken) by PeerTube so you don't need to provide an OAuth token in the request header.
      schema:
        type: string
    reinjectVideoFileToken:
      name: reinjectVideoFileToken
      in: query
      required: false
      description: Ask the server to reinject videoFileToken in URLs in m3u8 playlist
      schema:
        type: boolean
    videoPlaylistType:
      name: playlistType
      in: query
      required: false
      schema:
        $ref: '#/components/schemas/VideoPlaylistTypeSet'
    registrationTokenId:
      name: registrationTokenId
      in: path
      required: true
      schema:
        type: integer
    runnerId:
      name: runnerId
      in: path
      required: true
      schema:
        type: integer
    jobUUID:
      name: jobUUID
      in: path
      required: true
      schema:
        $ref: '#/components/schemas/UUIDv4'
    passwordId:
      name: passwordId
      in: path
      required: true
      description: The video password id
      schema:
        $ref: '#/components/schemas/id'
    onLocalVideo:
      name: onLocalVideo
      in: query
      required: false
      schema:
        type: boolean
      description: 'Display only objects of local or remote videos'
    includeMuted:
      name: includeMuted
      in: query
      required: false
      schema:
        type: boolean
      description: '**PeerTube >= 8.2** Include comments from muted accounts'
    videoChannelId:
      name: videoChannelId
      in: query
      required: false
      schema:
        type: integer
      description: 'Limit results on this specific video channel'
    videoId:
      name: videoId
      in: query
      required: false
      schema:
        type: integer
      description: 'Limit results on this specific video'
    searchVideoForComments:
      name: searchVideo
      in: query
      required: false
      description: Filter comments by searching on the video
      schema:
        type: string
    searchAccountForComments:
      name: searchAccount
      in: query
      required: false
      description: Filter comments by searching on the account
      schema:
        type: string
    videoPasswordHeader:
      name: x-peertube-video-password
      description: Required on password protected video
      in: header
      required: false
      schema:
        type: string
    resumableUploadInitContentLengthHeader:
        name: X-Upload-Content-Length
        in: header
        schema:
          type: number
          example: 2469036
        required: true
        description: Number of bytes that will be uploaded in subsequent requests. Set this value to the size of the file you are uploading.
    resumableUploadInitContentTypeHeader:
      name: X-Upload-Content-Type
      in: header
      schema:
        type: string
        format: mimetype
        example: video/mp4
      required: true
      description: MIME type of the file that you are uploading. Depending on your instance settings, acceptable values might vary.
    resumableUploadChunkContentRangeHeader:
      name: Content-Range
      in: header
      schema:
        type: string
        example: bytes 0-262143/2469036
      required: true
      description: |
        Specifies the bytes in the file that the request is uploading.

        For example, a value of `bytes 0-262143/1000000` shows that the request is sending the first
        262144 bytes (256 x 1024) in a 2,469,036 byte file.

        When the server config `client.videos.resumableUpload.minChunkSize` (video uploads) or
        `import.users.resumableUpload.minChunkSize` (user archive imports) is not `0`,
        every chunk except the last one must be at least that big. It must also be at least 1/10,000 of the file size
        (the maximum number of object storage multipart upload parts).
    resumableUploadChunkContentLengthHeader:
      name: Content-Length
      in: header
      schema:
        type: number
        example: 262144
      required: true
      description: |
        Size of the chunk that the request is sending.

        Remember that larger chunks are more efficient. PeerTube's web client uses chunks varying from
        1048576 bytes (~1MB) and increases or reduces size depending on connection health.
    resumableUploadId:
      name: upload_id
      in: query
      required: true
      description: |
        Created session id to proceed with. If you didn't send chunks in the last hour, it is
        not valid anymore and you need to initialize a new upload.
      schema:
        type: string
    logoTypeParam:
      name: logoType
      in: path
      required: true
      schema:
        type: string
        enum:
          - 'favicon'
          - 'header-wide'
          - 'header-square'
          - 'opengraph'
    includeCollaborations:
      name: includeCollaborations
      in: query
      required: false
      description: "**PeerTube >= 8.0** Include objects from collaborated channels"
      schema:
        type: boolean
    collaboratorId:
      name: collaboratorId
      in: path
      required: true
      description: The collaborator id
      schema:
        $ref: '#/components/schemas/id'

  securitySchemes:
    OAuth2:
      description: |
        Authenticating via OAuth requires the following steps:
        - Have an activated account
        - [Generate] an access token for that account at `/api/v1/users/token`.
        - Make requests with the *Authorization: Bearer <token\>* header
        - Profit, depending on the role assigned to the account

        Note that the __access token is valid for 1 day__ and is given
        along with a __refresh token valid for 2 weeks__.

        [Generate]: https://docs.joinpeertube.org/api/rest-getting-started
      type: oauth2
      flows:
        password:
          tokenUrl: /api/v1/users/token
          scopes:
            admin: Admin scope
            moderator: Moderator scope
            user: User scope
  schemas:
    # Reusable core properties
    id:
      type: integer
      minimum: 1
      example: 42
    UUIDv4:
      type: string
      format: uuid
      example: 9c9de5e8-0a1e-484a-b099-e80766180a6d
      pattern: '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'
      minLength: 36
      maxLength: 36
    shortUUID:
      type: string
      description: translation of a uuid v4 with a bigger alphabet to have a shorter uuid
      example: 2y84q2MQUMWPbiEcxNXMgC
    username:
      type: string
      description: immutable name of the user, used to find or mention its actor
      example: chocobozzz
      pattern: '/^[a-z0-9._]+$/'
      minLength: 1
      maxLength: 50
    usernameChannel:
      type: string
      description: immutable name of the channel, used to interact with its actor
      example: framasoft_videos
      pattern: '/^[a-zA-Z0-9\\-_.:]+$/'
      minLength: 1
      maxLength: 50
    password:
      type: string
      format: password
      minLength: 6
      maxLength: 50
    currentPassword:
      type: string
      format: password
      description: Password of the authenticated user, required if [password confirmation](#section/Password-confirmation) is enabled

    VideoCategorySet:
      type: integer
      description: category id of the video (see [/videos/categories](#operation/getCategories))
      example: 15
    VideoConstantNumber-Category:
      properties:
        id:
          $ref: '#/components/schemas/VideoCategorySet'
        label:
          type: string
          example: Science & Technology

    VideoLicenceSet:
      type: integer
      description: licence id of the video (see [/videos/licences](#operation/getLicences))
      example: 2
    VideoConstantNumber-Licence:
      properties:
        id:
          $ref: '#/components/schemas/VideoLicenceSet'
        label:
          type: string
          example: Attribution - Share Alike

    VideoLanguageSet:
      type: string
      description: language id of the video (see [/videos/languages](#operation/getLanguages))
      example: en
    VideoConstantString-Language:
      properties:
        id:
          $ref: '#/components/schemas/VideoLanguageSet'
        label:
          type: string
          example: English

    VideoPlaylistPrivacySet:
      type: integer
      enum:
        - 1
        - 2
        - 3
      description: Video playlist privacy policy (see [/video-playlists/privacies](#operation/getPlaylistPrivacyPolicies))
    VideoPlaylistPrivacyConstant:
      properties:
        id:
          $ref: '#/components/schemas/VideoPlaylistPrivacySet'
        label:
          type: string

    VideoPlaylistTypeSet:
      type: integer
      enum:
        - 1
        - 2
      description: The video playlist type (Regular = `1`, Watch Later = `2`)
    VideoPlaylistTypeConstant:
      properties:
        id:
          $ref: '#/components/schemas/VideoPlaylistTypeSet'
        label:
          type: string

    VideoPrivacySet:
      type: integer
      enum:
        - 1
        - 2
        - 3
        - 4
        - 5
      description: privacy id of the video (see [/videos/privacies](#operation/getVideoPrivacyPolicies))
    VideoPrivacyConstant:
      properties:
        id:
          $ref: '#/components/schemas/VideoPrivacySet'
        label:
          type: string

    VideoCommentsPolicySet:
      type: integer
      enum:
        - 1
        - 2
        - 3
      description: Comments policy of the video (Enabled = `1`, Disabled = `2`, Requires Approval = `3`)
    VideoCommentsPolicyConstant:
      properties:
        id:
          $ref: '#/components/schemas/VideoCommentsPolicySet'
        label:
          type: string

    VideoRecommendationScopeSet:
      type: integer
      enum:
        - 1
        - 2
        - 3
        - 4
      description: |
        Videos that can be recommended next to a video:
          - `1` All videos
          - `2` Only videos of the platform that owns the reference video (or of the current platform if no video is given)
          - `3` Only videos of the account that owns the reference video
          - `4` Only videos of the channel of the reference video

        This is a preference of the video owner: applications displaying recommendations may not apply it
    VideoRecommendationScopeConstant:
      properties:
        id:
          $ref: '#/components/schemas/VideoRecommendationScopeSet'
        label:
          type: string

    VideoAIUsageSet:
      type: integer
      enum:
        - 1
        - 2
        - 3
        - 4
      description: |
        **PeerTube >= 9.0** Use of AI in the video, declared by the video creator:
          - `1` Not specified
          - `2` No AI-generated content: nothing seen or heard in the video has been generated by AI
          - `3` Contains AI-generated content: some parts of the video have been generated by AI
          - `4` AI-generated: the whole video, or most of it, has been generated by AI
    VideoAIUsageConstant:
      properties:
        id:
          $ref: '#/components/schemas/VideoAIUsageSet'
        label:
          type: string
    VideoCommercialContentSet:
      type: integer
      enum:
        - 1
        - 2
        - 3
      description: |
        **PeerTube >= 9.0** Commercial content in the video, declared by the video creator:
          - `1` None
          - `2` Promotional content: the creator promotes their own products, services or business
          - `3` Paid partnership: a third party paid, or provided goods or services, in exchange for the promotion
    VideoCommercialContentConstant:
      properties:
        id:
          $ref: '#/components/schemas/VideoCommercialContentSet'
        label:
          type: string

    BlockStatus:
      properties:
        accounts:
          type: object
          additionalProperties:
            x-additionalPropertiesName: account
            type: object
            properties:
              blockedByServer:
                type: boolean
              blockedByServerSubscription:
                type: string
              blockedByUser:
                type: boolean
        hosts:
          type: object
          additionalProperties:
            x-additionalPropertiesName: host
            type: object
            properties:
              blockedByServer:
                type: boolean
              blockedByServerSubscription:
                type: string
              blockedByUser:
                type: boolean

    NSFWPolicy:
      type: string
      enum:
        - display
        - warn
        - do_not_list

    NSFWFlag:
      type: integer
      enum:
        - 0
        - 1
        - 2
        - 4
      description: >

        NSFW flags (can be combined using bitwise or operator)

        - `0` NONE

        - `1` VIOLENT

        - `2` EXPLICIT_SEX

    UserRole:
      type: integer
      enum:
        - 0
        - 1
        - 2
      description: 'The user role (Admin = `0`, Moderator = `1`, User = `2`)'
      example: 2
    UserAdminFlags:
      type: integer
      enum:
        - 0
        - 1
      description: 'Admin flags for the user (None = `0`, Bypass video blocklist = `1`)'
      example: 1

    LiveVideoLatencyMode:
      type: integer
      enum:
        - 1
        - 2
        - 3
      description: 'The live latency mode (Default = `1`, High latency = `2`, Small Latency = `3`)'

    LiveVideoReplaySettings:
      type: object
      properties:
        privacy:
          # description: Video playlist privacy policy (see [../video-playlists/privacies])
          $ref: '#/components/schemas/VideoPrivacySet'

    VideoChannelActivityAction:
      type: integer
      enum:
        - 1
        - 2
        - 3
        - 4
        - 5
        - 6
        - 7
        - 8
        - 9
        - 10
        - 11
      description: |
        The activity action:
          - CREATE: 1
          - UPDATE: 2
          - DELETE: 3
          - UPDATE_CAPTIONS: 4
          - UPDATE_CHAPTERS: 5
          - UPDATE_PASSWORDS: 6
          - CREATE_STUDIO_TASKS: 7
          - UPDATE_SOURCE_FILE: 8
          - UPDATE_ELEMENTS: 9
          - REMOVE_CHANNEL_OWNERSHIP: 10
          - CREATE_CHANNEL_OWNERSHIP: 11

    VideoChannelActivityTarget:
      type: integer
      enum:
        - 1
        - 2
        - 3
        - 4
        - 5
      description: |
        The activity target:
          - VIDEO: 1,
          - PLAYLIST: 2,
          - CHANNEL: 3,
          - CHANNEL_SYNC: 4,
          - VIDEO_IMPORT: 5

    VideoStateConstant:
      properties:
        id:
          type: integer
          enum:
            - 1
            - 2
            - 3
            - 4
            - 5
            - 6
            - 7
            - 8
            - 9
            - 10
            - 11
            - 12
            - 13
            - 14
            - 15
          description: |
            The video state:
            - `1`: Published
            - `2`: To transcode
            - `3`: To import
            - `4`: Waiting for live stream
            - `5`: Live ended
            - `6`: To move to an external storage (object storage...)
            - `7`: Transcoding failed
            - `8`: Moving to an external storage failed
            - `9`: To edit using studio edition feature
            - `10`: To move to the file system
            - `11`: Moving to the file system failed
            - `12`: Import failed
            - `13`: To duplicate, the files of another video are being copied
            - `14`: Duplication failed, the files of the other video could not be copied
            - `15`: The studio edition of a video saved as a new video failed
        label:
          type: string

    UserExportState:
      type: integer
      enum:
        - 1
        - 2
        - 3
        - 4
      description: |
        The user export state:
          - `1`: Pending
          - `2`: Processing
          - `3`: Completed
          - `4`: Errored

    UserImportState:
      type: integer
      enum:
        - 1
        - 2
        - 3
        - 4
      description: |
        The user import state:
          - `1`: Pending
          - `2`: Processing
          - `3`: Completed
          - `4`: Errored

    AbuseStateSet:
      type: integer
      enum:
        - 1
        - 2
        - 3
      description: 'The abuse state (Pending = `1`, Rejected = `2`, Accepted = `3`)'
    AbuseStateConstant:
      properties:
        id:
          $ref: '#/components/schemas/AbuseStateSet'
        label:
          type: string
    AbusePredefinedReasons:
      type: array
      items:
        type: string
        enum:
        - violentOrAbusive
        - hatefulOrAbusive
        - spamOrMisleading
        - privacy
        - rights
        - serverRules
        - thumbnails
        - captions
      example: [spamOrMisleading]

    VideoResolutionSet:
      type: integer
      description: |
        Video resolution (`0`, `240`, `360`, `720`, `1080`, `1440` or `2160`)

        `0` is used as a special value for stillimage videos dedicated to audio, a.k.a. audio-only videos.
      example: 240
    VideoResolutionConstant:
      description: resolutions and their labels for the video
      properties:
        id:
          $ref: '#/components/schemas/VideoResolutionSet'
        label:
          type: string
          example: 240p
    VideoScheduledUpdate:
      properties:
        privacy:
          $ref: '#/components/schemas/VideoPrivacySet'
        updateAt:
          type: string
          format: date-time
          description: When to update the video
      required:
        - updateAt
    AccountSummary:
      properties:
        id:
          type: integer
        name:
          type: string
        displayName:
          type: string
        url:
          type: string
          format: url
        host:
          type: string
          format: hostname
        avatars:
          type: array
          items:
            $ref: '#/components/schemas/ActorImage'

    VideoSummary:
      properties:
        id:
          description: object id for the video
          allOf:
            - $ref: '#/components/schemas/id'
        uuid:
          description: universal identifier for the video, that can be used across instances
          allOf:
            - $ref: '#/components/schemas/UUIDv4'
        shortUUID:
          allOf:
            - $ref: '#/components/schemas/shortUUID'
        name:
          type: string
        isLive:
          type: boolean
        nsfw:
          type: boolean
        publishedAt:
          type: string
          format: date-time
        thumbnails:
          description: "**PeerTube >= 8.1** Array of thumbnails for the video"
          type: array
          items:
            $ref: '#/components/schemas/Thumbnail'
        channel:
          $ref: '#/components/schemas/VideoChannelSummary'

    VideoChannelSummary:
      properties:
        id:
          $ref: '#/components/schemas/id'
        name:
          type: string
        displayName:
          type: string
        url:
          type: string
          format: url
        host:
          type: string
          format: hostname
        avatars:
          type: array
          items:
            $ref: '#/components/schemas/ActorImage'
    PlaylistElement:
      properties:
        position:
          type: integer
        startTimestamp:
          type: integer
          format: seconds
        stopTimestamp:
          type: integer
          format: seconds
        video:
          nullable: true
          allOf:
            - $ref: '#/components/schemas/Video'
    Thumbnail:
      properties:
        fileUrl:
          type: string
        width:
          type: integer
        height:
          type: integer
        aspectRatio:
          type: string
          example: '16:9'
    VideoFile:
      properties:
        id:
          $ref: '#/components/schemas/id'
        magnetUri:
          type: string
          format: uri
          description: magnet URI allowing to resolve the video via BitTorrent without a metainfo file
          pattern: /magnet:\?xt=urn:[a-z0-9]+:[a-z0-9]{32}/i
        resolution:
          $ref: '#/components/schemas/VideoResolutionConstant'
        size:
          type: integer
          description: Video file size in bytes
        torrentUrl:
          type: string
          description: Direct URL of the torrent file
          format: url
        torrentDownloadUrl:
          type: string
          description: URL endpoint that transfers the torrent file as an attachment (so that the browser opens a download dialog)
          format: url
        fileUrl:
          type: string
          description: Direct URL of the video
          format: url
        playlistUrl:
          type: string
          description: Playlist URL of the file if it is owned by a playlist
          format: url
        fileDownloadUrl:
          type: string
          description: URL endpoint that transfers the video file as an attachment (so that the browser opens a download dialog)
          format: url
        fps:
          type: number
          description: Frames per second of the video file
        width:
          type: number
          description: "**PeerTube >= 6.1** Video stream width"
        height:
          type: number
          description: "**PeerTube >= 6.1** Video stream height"
        metadataUrl:
          type: string
          format: url
          description: URL dereferencing the output of ffprobe on the file
        hasAudio:
          type: boolean
          description: "**PeerTube >= 6.2** The file container has an audio stream"
        hasVideo:
          type: boolean
          description: "**PeerTube >= 6.2** The file container has a video stream"
        storage:
          $ref: '#/components/schemas/FileStorage'

    VideoStreamingPlaylists:
      allOf:
        - type: object
          properties:
            id:
              $ref: '#/components/schemas/id'
            type:
              type: integer
              enum:
                - 1
              description: |
                Playlist type:
                - `1`: HLS
        - $ref: '#/components/schemas/VideoStreamingPlaylists-HLS'
    VideoStreamingPlaylists-HLS:
      properties:
        playlistUrl:
          type: string
          format: url
        segmentsSha256Url:
          type: string
          format: url
        files:
          type: array
          description: |
            Video files associated to this playlist.

            The difference with the root `files` property is that these files are fragmented, so they can be used in this streaming playlist (HLS, etc.)
          items:
            $ref: '#/components/schemas/VideoFile'
        redundancies:
          type: array
          items:
            type: object
            properties:
              baseUrl:
                type: string
                format: url
    VideoInfo:
      properties:
        id:
          $ref: '#/components/schemas/Video/properties/id'
        uuid:
          $ref: '#/components/schemas/Video/properties/uuid'
        name:
          $ref: '#/components/schemas/Video/properties/name'
        state:
          $ref: '#/components/schemas/Video/properties/state'
    Video:
      properties:
        id:
          description: object id for the video
          allOf:
            - $ref: '#/components/schemas/id'
        uuid:
          description: universal identifier for the video, that can be used across instances
          allOf:
            - $ref: '#/components/schemas/UUIDv4'
        shortUUID:
          allOf:
            - $ref: '#/components/schemas/shortUUID'
        isLive:
          type: boolean
        liveSchedules:
          type: array
          items:
            $ref: '#/components/schemas/LiveSchedule'
        createdAt:
          type: string
          format: date-time
          example: 2017-10-01T10:52:46.396Z
          description: time at which the video object was first drafted
        publishedAt:
          type: string
          format: date-time
          example: 2018-10-01T10:52:46.396Z
          description: time at which the video was marked as ready for playback (with restrictions depending on `privacy`). Usually set after a `state` evolution.
        updatedAt:
          type: string
          format: date-time
          example: 2021-05-04T08:01:01.502Z
          description: last time the video's metadata was modified
        originallyPublishedAt:
          type: string
          nullable: true
          format: date-time
          example: 2010-10-01T10:52:46.396Z
          description: used to represent a date of first publication, prior to the practical publication date of `publishedAt`
        category:
          allOf:
            - $ref: '#/components/schemas/VideoConstantNumber-Category'
          description: category in which the video is classified
        licence:
          allOf:
            - $ref: '#/components/schemas/VideoConstantNumber-Licence'
          description: licence under which the video is distributed
        language:
          allOf:
            - $ref: '#/components/schemas/VideoConstantString-Language'
          description: main language used in the video
        privacy:
          allOf:
            - $ref: '#/components/schemas/VideoPrivacyConstant'
          description: privacy policy used to distribute the video
        truncatedDescription:
          type: string
          nullable: true
          example: |
            **[Want to help to translate this video?](https://weblate.framasoft.org/projects/what-is-peertube-video/)**\r\n\r\n
            **Take back the control of your videos! [#JoinPeertube](https://joinpeertube.org)**\r\n*A decentralized video hosting network, based on fr...
          minLength: 3
          maxLength: 250
          description: |
            truncated description of the video, written in Markdown.
        duration:
          type: integer
          example: 1419
          format: seconds
          description: duration of the video in seconds
        aspectRatio:
          type: number
          nullable: true
          format: float
          example: 1.778
          description: "**PeerTube >= 6.1** Aspect ratio of the video stream"
        isLocal:
          type: boolean
        name:
          type: string
          description: title of the video
          example: What is PeerTube?
          minLength: 3
          maxLength: 120
        thumbnailPath:
          description: "Deprecated in PeerTube v8.1, use thumbnails instead. Null if the file is stored in object storage: use the non-deprecated field instead."
          deprecated: true
          nullable: true
          type: string
        previewPath:
          description: "Deprecated in PeerTube v8.1, use thumbnails instead. Null if the file is stored in object storage: use the non-deprecated field instead."
          deprecated: true
          nullable: true
          type: string
        thumbnails:
          description: "**PeerTube >= 8.1** Array of thumbnails for the video"
          type: array
          items:
            $ref: '#/components/schemas/Thumbnail'
        embedPath:
          type: string
          example: /videos/embed/a65bc12f-9383-462e-81ae-8207e8b434ee
        views:
          type: integer
          example: 1337
        likes:
          type: integer
          example: 42
        dislikes:
          type: integer
          example: 7
        comments:
          description: "**PeerTube >= 7.2** Number of comments on the video"
          type: integer
        nsfw:
          type: boolean
        nsfwFlags:
          allOf:
            - $ref: '#/components/schemas/NSFWFlag'
        nsfwSummary:
          type: string
          description: "**PeerTube >= 7.2** More information about the sensitive content of the video"
        aiUsage:
          $ref: '#/components/schemas/VideoAIUsageConstant'
        commercialContent:
          $ref: '#/components/schemas/VideoCommercialContentConstant'
        recommendationScope:
          $ref: '#/components/schemas/VideoRecommendationScopeConstant'
        waitTranscoding:
          type: boolean
          nullable: true
        state:
          allOf:
            - $ref: '#/components/schemas/VideoStateConstant'
          description: represents the internal state of the video processing within the PeerTube instance
        scheduledUpdate:
          nullable: true
          allOf:
            - $ref: '#/components/schemas/VideoScheduledUpdate'
        blacklisted:
          nullable: true
          type: boolean
        blacklistedReason:
          nullable: true
          type: string
        account:
          $ref: '#/components/schemas/AccountSummary'
        channel:
          $ref: '#/components/schemas/VideoChannelSummary'
        userHistory:
          nullable: true
          type: object
          properties:
            currentTime:
              type: integer
        captionLanguages:
          description: "**PeerTube >= 9.0** Languages of the video captions. Only returned by video lists"
          type: array
          items:
            type: string
            example: fr
    ServerError:
      properties:
        type:
          type: string
          format: uri-reference
          description: >
            URI identifying the error type. `about:blank` when the error has no specific type.
            Otherwise it links to the corresponding section of the [Errors](#section/Errors) documentation;
            the type name itself is also available in `code`.
          example: 'https://docs.joinpeertube.org/api-rest-reference.html#section/Errors/video_requires_password'
        detail:
          type: string
          example: 'Please provide a password to access this password protected video'
        status:
          type: integer
          example: 403
        code:
          type: string
          example: video_requires_password
    VideoDetails:
      allOf:
        - $ref: '#/components/schemas/Video'
        - type: object
          properties:
            viewers:
              type: integer
              description: If the video is a live, you have the amount of current viewers
            description:
              type: string
              nullable: true
              example: |
                "**[Want to help to translate this video?](https://weblate.framasoft.org/projects/what-is-peertube-video/)**\r\n\r\n
                **Take back the control of your videos! [#JoinPeertube](https://joinpeertube.org)**\r\n*A decentralized video hosting network,
                based on free/libre software!*\r\n\r\n**Animation Produced by:** [LILA](https://libreart.info) - [ZeMarmot Team](https://film.zemarmot.net)\r\n
                *Directed by* Aryeom\r\n*Assistant* Jehan\r\n**Licence**: [CC-By-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)\r\n\r\n
                **Sponsored by** [Framasoft](https://framasoft.org)\r\n\r\n**Music**: [Red Step Forward](http://play.dogmazic.net/song.php?song_id=52491) - CC-By Ken Bushima\r\n\r\n
                **Movie Clip**: [Caminades 3: Llamigos](http://www.caminandes.com/) CC-By Blender Institute\r\n\r\n**Video sources**: https://gitlab.gnome.org/Jehan/what-is-peertube/"
              minLength: 3
              maxLength: 1000
              description: |
                full description of the video, written in Markdown.
            support:
              type: string
              nullable: true
              description: A text tell the audience how to support the video creator
              example: Please support our work on https://soutenir.framasoft.org/en/ <3
              minLength: 3
              maxLength: 1000
            channel:
              $ref: '#/components/schemas/VideoChannel'
            account:
              $ref: '#/components/schemas/Account'
            tags:
              example: [flowers, gardening]
              type: array
              minItems: 1
              maxItems: 5
              items:
                type: string
                minLength: 2
                maxLength: 30
            commentsPolicy:
              $ref: '#/components/schemas/VideoCommentsPolicyConstant'
            downloadEnabled:
              type: boolean
            inputFileUpdatedAt:
              type: string
              format: date-time
              nullable: true
              description: Latest input file update. Null if the file has never been replaced since the original upload
            trackerUrls:
              type: array
              description: |
                WebTorrent (`ws://` or `wss://`) and BitTorrent (`http://` or `https://`) trackers of the video
              items:
                type: string
                format: url
              example:
                - https://peertube2.cpy.re/tracker/announce
                - wss://peertube2.cpy.re/tracker/socket
            files:
              type: array
              items:
                $ref: '#/components/schemas/VideoFile'
              description: |
                Web compatible video files. If Web Video is disabled on the server:

                - field will be empty
                - video files will be found in `streamingPlaylists[].files` field
            streamingPlaylists:
              type: array
              items:
                $ref: '#/components/schemas/VideoStreamingPlaylists'
              description: |
                HLS playlists/manifest files. If HLS is disabled on the server:

                - field will be empty
                - video files will be found in `files` field
    FileRedundancyInformation:
      properties:
        id:
          $ref: '#/components/schemas/id'
        fileUrl:
          type: string
          format: url
        strategy:
          type: string
          enum:
            - manual
            - most-views
            - trending
            - recently-added
        size:
          type: integer
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        expiresOn:
          type: string
          format: date-time
    VideoRedundancy:
      properties:
        id:
          $ref: '#/components/schemas/id'
        name:
          type: string
        url:
          type: string
          format: url
        uuid:
          $ref: '#/components/schemas/UUIDv4'
        redundancies:
          type: object
          properties:
            streamingPlaylists:
              type: array
              items:
                $ref: '#/components/schemas/FileRedundancyInformation'
    AccountBlock:
      properties:
        byAccount:
          $ref: '#/components/schemas/Account'
        blockedAccount:
          $ref: '#/components/schemas/Account'
          type: boolean
        blocklistSubscription:
          $ref: '#/components/schemas/BlocklistSubscriptionSummary'
          nullable: true
        createdAt:
          type: string
          format: date-time
    ServerBlock:
      properties:
        byAccount:
          $ref: '#/components/schemas/Account'
        blockedServer:
          type: object
          properties:
            host:
              type: string
              format: hostname
        blocklistSubscription:
          $ref: '#/components/schemas/BlocklistSubscriptionSummary'
          nullable: true
        createdAt:
          type: string
          format: date-time
    BlocklistSubscription:
      properties:
        id:
          $ref: '#/components/schemas/id'
        name:
          type: string
        url:
          type: string
          format: url
        mutedAccountsCount:
          type: integer
          minimum: 0
        mutedServersCount:
          type: integer
          minimum: 0
        lastSyncAt:
          type: string
          format: date-time
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
    BlocklistSubscriptionSummary:
      properties:
        id:
          $ref: '#/components/schemas/id'
        name:
          type: string
        url:
          type: string
          format: url
    BlocklistLog:
      properties:
        id:
          $ref: '#/components/schemas/id'
        action:
          type: string
          enum:
            - add
            - delete
        target:
          type: string
        createdAt:
          type: string
          format: date-time
    AutoMuteList:
      properties:
        name:
          type: string
        actions:
          type: array
          items:
            type: object
            properties:
              type:
                type: string
                enum:
                  - block
                  - unblock
              target:
                type: string
              createdAt:
                type: string
                format: date-time
    CommentAutoTagPolicies:
      properties:
        review:
          type: array
          description: 'Auto tags that automatically set the comment in review state'
          items:
            type: string
    VideoAutoTagPolicies:
      properties:
        autoBlock:
          type: array
          description: 'Auto tags that will automatically block videos matching these tags'
          items:
            type: string
    AutomaticTagAvailable:
      properties:
        available:
          type: array
          description: 'Available auto tags that can be used to filter objects or set a comment in review state'
          items:
            type: object
            properties:
              name:
                type: string
                description: tag name
              type:
                type: string
                enum:
                  - 'core'
                  - 'watched-words-list'

    VideoImportStateConstant:
      properties:
        id:
          type: integer
          enum:
            - 1
            - 2
            - 3
            - 4
            - 5
            - 6
          description: >
            The video import state (Pending = `1`, Success = `2`, Failed = `3`, Rejected = `4`, Cancelled = `5`,
            Processing = `6`)
        label:
          type: string
          example: Pending
    VideoCreateImport:
      allOf:
        - type: object
          additionalProperties: false
          oneOf:
            - properties:
                targetUrl:
                  $ref: '#/components/schemas/VideoImport/properties/targetUrl'
              required: [targetUrl]
            - properties:
                magnetUri:
                  $ref: '#/components/schemas/VideoImport/properties/magnetUri'
              required: [magnetUri]
            - properties:
                torrentfile:
                  $ref: '#/components/schemas/VideoImport/properties/torrentfile'
              required: [torrentfile]
        - $ref: '#/components/schemas/VideoUploadRequestCommon'
      required:
        - channelId
        - name
    VideoImport:
      properties:
        id:
          $ref: '#/components/schemas/id'
        targetUrl:
          type: string
          format: url
          description: remote URL where to find the import's source video
          example: https://framatube.org/videos/watch/9c9de5e8-0a1e-484a-b099-e80766180a6d
        magnetUri:
          type: string
          format: uri
          description: magnet URI allowing to resolve the import's source video
          pattern: /magnet:\?xt=urn:[a-z0-9]+:[a-z0-9]{32}/i
        torrentfile:
          type: string
          format: binary
          description: Torrent file containing only the video file
        torrentName:
          type: string
        state:
          allOf:
            - $ref: '#/components/schemas/VideoImportStateConstant'
        error:
          type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        video:
          nullable: true
          allOf:
            - $ref: '#/components/schemas/Video'
    VideoImportsList:
      properties:
        total:
          type: integer
          example: 1
        data:
          type: array
          maxItems: 100
          items:
            $ref: '#/components/schemas/VideoImport'
    Abuse:
      properties:
        id:
          $ref: '#/components/schemas/id'
        reason:
          type: string
          example: The video is a spam
          minLength: 2
          maxLength: 3000
        predefinedReasons:
          $ref: '#/components/schemas/AbusePredefinedReasons'
        reporterAccount:
          $ref: '#/components/schemas/Account'
        state:
          $ref: '#/components/schemas/AbuseStateConstant'
        moderationComment:
          type: string
          example: Decided to ban the server since it spams us regularly
          minLength: 2
          maxLength: 3000
        video:
          type: object
          properties:
            id:
              type: integer
            uuid:
              $ref: '#/components/schemas/UUIDv4'
            shortUUID:
              $ref: '#/components/schemas/shortUUID'
            name:
              type: string
            nsfw:
              type: boolean
            startAt:
              type: string
              format: date-time
            endAt:
              type: string
              format: date-time
            deleted:
              type: boolean
            blacklisted:
              type: boolean
            thumbnailPath:
              description: "Deprecated in PeerTube v8.1, use thumbnails instead. Null if the file is stored in object storage: use the non-deprecated field instead."
              deprecated: true
              nullable: true
              type: string
            thumbnails:
              description: "**PeerTube >= 8.1** Array of thumbnails for the video"
              type: array
              items:
                $ref: '#/components/schemas/Thumbnail'
            channel:
              $ref: '#/components/schemas/VideoChannel'
        createdAt:
          type: string
          format: date-time
    AbuseMessage:
      properties:
        id:
          $ref: '#/components/schemas/id'
        message:
          type: string
          minLength: 2
          maxLength: 3000
        byModerator:
          type: boolean
        createdAt:
          type: string
          format: date-time
        account:
          $ref: '#/components/schemas/AccountSummary'
    VideoBlacklist:
      type: object
      properties:
        id:
          $ref: '#/components/schemas/id'
        reason:
          type: string
          description: Reason for the block (public)
        internalNote:
          type: string
          description: Internal note for moderators/admins
        unfederated:
          type: boolean
        type:
          type: integer
          description: >
            - `1`: manual block
            - `2`: automatic block by instance policy
            - `3`: automatic block by auto-tag policy
        video:
          $ref: '#/components/schemas/Video'
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
    VideoBlacklistCreate:
      type: object
      properties:
        reason:
          type: string
          description: Reason for the block (public)
        unfederate:
          type: boolean
          description: Whether to unfederate the video
        internalNote:
          type: string
          description: Internal note for moderators/admins
    VideoBlacklistUpdate:
      type: object
      properties:
        reason:
          type: string
          description: Reason for the block (displayed publicly)
        internalNote:
          type: string
          description: Internal note for moderators/admins
    ChangeOwnership:
      type: object
      description: Representation of a ownership change
      properties:
        id:
          $ref: '#/components/schemas/id'
        state:
          properties:
            id:
              $ref: '#/components/schemas/ChangeOwnershipState'
            label:
              type: string
        initiatorAccount:
          $ref: '#/components/schemas/Account'
        nextOwnerAccount:
          $ref: '#/components/schemas/Account'
        video:
          $ref: '#/components/schemas/VideoSummary'
        videoChannel:
          $ref: '#/components/schemas/VideoChannelSummary'
        createdAt:
          type: string
          format: date-time
    VideoPlaylist:
      properties:
        id:
          $ref: '#/components/schemas/id'
        uuid:
          $ref: '#/components/schemas/UUIDv4'
        shortUUID:
          allOf:
            - $ref: '#/components/schemas/shortUUID'
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        description:
          type: string
          minLength: 3
          maxLength: 1000
        displayName:
          type: string
          minLength: 1
          maxLength: 120
        isLocal:
          type: boolean
        videoLength:
          type: integer
          minimum: 0
        thumbnailPath:
          description: "Deprecated in PeerTube v8.1, use thumbnails instead. Null if the file is stored in object storage: use the non-deprecated field instead."
          deprecated: true
          nullable: true
          type: string
        thumbnails:
          description: "**PeerTube >= 8.1** Array of thumbnails for the playlist"
          type: array
          items:
            $ref: '#/components/schemas/Thumbnail'
        privacy:
          $ref: '#/components/schemas/VideoPlaylistPrivacyConstant'
        type:
          $ref: '#/components/schemas/VideoPlaylistTypeConstant'
        ownerAccount:
          $ref: '#/components/schemas/AccountSummary'
        videoChannel:
          $ref: '#/components/schemas/VideoChannelSummary'
        videoChannelPosition:
          type: integer
          minimum: 1
          description: Position of the playlist in the channel
    VideoComment:
      properties:
        id:
          $ref: '#/components/schemas/id'
        url:
          type: string
          format: url
        text:
          type: string
          format: html
          description: Text of the comment
          minLength: 1
          example: This video is wonderful!
        threadId:
          $ref: '#/components/schemas/id'
        inReplyToCommentId:
          nullable: true
          allOf:
            - $ref: '#/components/schemas/id'
        videoId:
          $ref: '#/components/schemas/Video/properties/id'
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        deletedAt:
          nullable: true
          type: string
          format: date-time
          default: null
        isDeleted:
          type: boolean
          default: false
        heldForReview:
          type: boolean
        totalRepliesFromVideoAuthor:
          type: integer
          minimum: 0
        totalReplies:
          type: integer
          minimum: 0
        account:
          $ref: '#/components/schemas/Account'
    VideoCommentThreadTree:
      properties:
        comment:
          $ref: '#/components/schemas/VideoComment'
        children:
          type: array
          description: >
            Direct replies of `comment`. The server truncates the tree in depth (see the `maxDepth` parameter) and in
            width, so this array may contain less elements than `totalChildren`. Missing replies can be fetched using
            `GET /api/v1/videos/{id}/comments/{commentId}/replies`
          items:
            $ref: '#/components/schemas/VideoCommentThreadTree'
        totalChildren:
          type: integer
          minimum: 0
          description: Total number of direct replies of `comment` the current user can see
    VideoCommentForOwnerOrAdmin:
      properties:
        id:
          $ref: '#/components/schemas/id'
        url:
          $ref: '#/components/schemas/VideoComment/properties/url'
        text:
          $ref: '#/components/schemas/VideoComment/properties/text'
        heldForReview:
          $ref: '#/components/schemas/VideoComment/properties/heldForReview'
        threadId:
          $ref: '#/components/schemas/VideoComment/properties/threadId'
        inReplyToCommentId:
          $ref: '#/components/schemas/VideoComment/properties/inReplyToCommentId'
        createdAt:
          $ref: '#/components/schemas/VideoComment/properties/createdAt'
        updatedAt:
          $ref: '#/components/schemas/VideoComment/properties/updatedAt'
        account:
          $ref: '#/components/schemas/VideoComment/properties/account'
        video:
          $ref: '#/components/schemas/VideoInfo'
        automaticTags:
          type: array
          items:
            type: string

    Storyboard:
      properties:
        storyboardPath:
          description: "Deprecated in PeerTube v8.0, use fileUrl instead. Null if the file is stored in object storage: use the non-deprecated field instead."
          deprecated: true
          nullable: true
          type: string
        fileUrl:
          description: "**PeerTube >= 7.1**"
          type: string
        totalHeight:
          type: integer
        totalWidth:
          type: integer
        spriteHeight:
          type: integer
        spriteWidth:
          type: integer
        spriteDuration:
          type: integer

    VideoCaption:
      properties:
        language:
          $ref: '#/components/schemas/VideoConstantString-Language'
        automaticallyGenerated:
          type: boolean
        captionPath:
          type: string
          deprecated: true
          nullable: true
          description: "Deprecated in PeerTube v8.0, use fileUrl instead. Null if the file is stored in object storage: use the non-deprecated field instead."
        fileUrl:
          description: "**PeerTube >= 7.1**"
          type: string
        m3u8Url:
          type: string
        updatedAt:
          type: string
          format: date-time

    VideoChapters:
      properties:
        chapters:
          type: object
          properties:
            title:
              type: string
            timecode:
              type: integer
    PodcastChapters:
      type: object
      description: Podcasting 2.0 JSON chapters, see https://github.com/Podcastindex-org/podcast-namespace/blob/main/docs/examples/chapters/jsonChapters.md
      properties:
        version:
          type: string
          example: '1.2.0'
        chapters:
          type: array
          items:
            type: object
            properties:
              startTime:
                type: integer
                description: Start of the chapter, in seconds
              title:
                type: string

    VideoSource:
      properties:
        inputFilename:
          type: string
          description: 'Uploaded/imported filename'
        fileDownloadUrl:
          type: string
          description: "**PeerTube >= 6.1** If enabled by the admin, the video source file is kept on the server and can be downloaded by the owner"
        resolution:
          description: "**PeerTube >= 6.1**"
          allOf:
           - $ref: '#/components/schemas/VideoResolutionConstant'
        size:
          type: integer
          description: "**PeerTube >= 6.1** Video file size in bytes"
        fps:
          type: number
          description: "**PeerTube >= 6.1** Frames per second of the video file"
        width:
          type: integer
          description: "**PeerTube >= 6.1** Video stream width"
        height:
          type: integer
          description: "**PeerTube >= 6.1** Video stream height"
        createdAt:
          type: string
          format: date-time
    ActorImage:
      properties:
        path:
          description: "Deprecated in PeerTube v8.0, use fileUrl instead. Null if the file is stored in object storage: use the non-deprecated field instead."
          deprecated: true
          nullable: true
          type: string
        fileUrl:
          description: "**PeerTube >= 7.1**"
          type: string
        width:
          type: integer
        height:
          type: integer
          description: "**PeerTube >= 7.3**"
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
    ActorInfo:
      properties:
        id:
          $ref: '#/components/schemas/id'
        name:
          type: string
        displayName:
          type: string
        host:
          type: string
          format: hostname
        avatars:
          type: array
          items:
            $ref: '#/components/schemas/ActorImage'
    Actor:
      properties:
        id:
          $ref: '#/components/schemas/id'
        url:
          type: string
          format: url
        name:
          description: immutable name of the actor, used to find or mention it
          allOf:
            - $ref: '#/components/schemas/username'
        avatars:
          type: array
          items:
            $ref: '#/components/schemas/ActorImage'
        host:
          type: string
          format: hostname
          description: server on which the actor is resident
        hostRedundancyAllowed:
          type: boolean
          nullable: true
          description: whether this actor's host allows redundancy of its videos
        followingCount:
          type: integer
          minimum: 0
          description: number of actors subscribed to by this actor, as seen by this instance
        followersCount:
          type: integer
          minimum: 0
          description: number of followers of this actor, as seen by this instance
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
    Account:
      allOf:
        - $ref: '#/components/schemas/Actor'
        - properties:
            userId:
              description: object id for the user tied to this account
              nullable: true
              allOf:
                - $ref: '#/components/schemas/User/properties/id'
            displayName:
              type: string
              description: editable name of the account, displayed in its representations
              minLength: 3
              maxLength: 120
            description:
              type: string
              nullable: true
              description: text or bio displayed on the account's profile
    UserViewingVideo:
      required:
        - currentTime
      properties:
        currentTime:
          type: integer
          format: seconds
          description: timestamp within the video, in seconds
          example: 5
        viewEvent:
          type: string
          enum:
            - seek
          description: >
            Event since last viewing call:
             * `seek` - If the user seeked the video
        sessionId:
          type: string
          description: >
            Optional param to represent the current viewer session.
            Used by the backend to properly count one view per session per video.
            PeerTube admin can configure the server to not trust this `sessionId` parameter but use the request IP address instead to identify a viewer.
        client:
          type: string
          description: >
            Client software used to watch the video. For example "Firefox", "PeerTube Approval Android", etc.
        device:
          description: >
            Device used to watch the video. For example "desktop", "mobile", "smarttv", etc.
          allOf:
            - $ref: '#/components/schemas/VideoStatsUserAgentDevice'
        operatingSystem:
          type: string
          description: >
            Operating system used to watch the video. For example "Windows", "Ubuntu", etc.

    VideoStatsOverall:
      properties:
        averageWatchTime:
          type: number
        totalWatchTime:
          type: number
        viewersPeak:
          type: number
        totalViewers:
          type: number
        viewersPeakDate:
          type: string
          format: date-time
        countries:
          type: array
          items:
            type: object
            properties:
              isoCode:
                type: string
              viewers:
                type: number
        subdivisions:
          type: array
          items:
            type: object
            properties:
              name:
                type: string
              viewers:
                type: number

    VideoStatsUserAgentDevice:
      enum:
        - 'console'
        - 'embedded'
        - 'mobile'
        - 'smarttv'
        - 'tablet'
        - 'wearable'
        - 'xr'
        - 'desktop'

    VideoStatsUserAgent:
      properties:
        clients:
          type: array
          items:
            type: object
            properties:
              name:
                type: string
              viewers:
                type: number
        devices:
          type: array
          items:
            type: object
            properties:
              name:
                $ref: '#/components/schemas/VideoStatsUserAgentDevice'
              viewers:
                type: number
        operatingSystem:
          type: array
          items:
            type: object
            properties:
              name:
                type: string
              viewers:
                type: number

    VideoStatsRetention:
      properties:
        data:
          type: array
          items:
            type: object
            properties:
              second:
                type: number
              retentionPercent:
                type: number

    VideoStatsTimeserie:
      properties:
        data:
          type: array
          items:
            type: object
            properties:
              date:
                type: string
              value:
                type: number

    ServerConfig:
      properties:
        instance:
          type: object
          properties:
            name:
              type: string
            shortDescription:
              type: string
            defaultClientRoute:
              type: string
            isNSFW:
              type: boolean
            defaultNSFWPolicy:
              type: string
            serverCountry:
              type: string
            defaultLanguage:
              type: string
            support:
              type: object
              properties:
                text:
                  type: string
            social:
              type: object
              properties:
                externalLink:
                  type: string
                mastodonLink:
                  type: string
                blueskyLink:
                  type: string
                xLink:
                  type: string
            customizations:
              type: object
              properties:
                javascript:
                  type: string
                css:
                  type: string
            avatars:
              type: array
              items:
                $ref: '#/components/schemas/ActorImage'
            banners:
              type: array
              items:
                $ref: '#/components/schemas/ActorImage'
        search:
          type: object
          properties:
            remoteUri:
              type: object
              properties:
                users:
                  type: boolean
                anonymous:
                  type: boolean
        plugin:
          type: object
          properties:
            registered:
              type: array
              items:
                type: string
        theme:
          type: object
          properties:
            registered:
              type: array
              items:
                type: string
        email:
          type: object
          properties:
            enabled:
              type: boolean
        contactForm:
          type: object
          properties:
            enabled:
              type: boolean
        serverVersion:
          type: string
        serverCommit:
          type: string
        signup:
          type: object
          properties:
            allowed:
              type: boolean
            allowedForCurrentIP:
              type: boolean
            requiresEmailVerification:
              type: boolean
        transcoding:
          type: object
          properties:
            hls:
              type: object
              properties:
                enabled:
                  type: boolean
            web_videos:
              type: object
              properties:
                enabled:
                  type: boolean
            enabledResolutions:
              type: array
              items:
                $ref: '#/components/schemas/VideoResolutionSet'
        import:
          type: object
          properties:
            videos:
              type: object
              properties:
                http:
                  type: object
                  properties:
                    enabled:
                      type: boolean
                torrent:
                  type: object
                  properties:
                    enabled:
                      type: boolean
            videoChannelSynchronization:
              type: object
              properties:
                enabled:
                  type: boolean
            users:
              type: object
              properties:
                enabled:
                  type: boolean
                resumableUpload:
                  type: object
                  properties:
                    minChunkSize:
                      type: number
                      description: In bytes. Minimum size of a user archive import chunk (except the last one), `0` if there is no minimum
        export:
          type: object
          properties:
            users:
              type: object
              properties:
                enabled:
                  type: boolean
                exportExpiration:
                  type: number
                  description: In milliseconds
                maxUserVideoQuota:
                  type: number
                  description: In bytes
        autoBlacklist:
          type: object
          properties:
            videos:
              type: object
              properties:
                ofUsers:
                  type: object
                  properties:
                    enabled:
                      type: boolean
        blocklist:
          type: object
          properties:
            publicLog:
              type: object
              properties:
                enabled:
                  type: boolean
        avatar:
          type: object
          properties:
            file:
              type: object
              properties:
                size:
                  type: object
                  properties:
                    max:
                      type: integer
            extensions:
              type: array
              items:
                type: string
        video:
          type: object
          properties:
            image:
              type: object
              properties:
                extensions:
                  type: array
                  items:
                    type: string
                size:
                  type: object
                  properties:
                    max:
                      type: integer
            file:
              type: object
              properties:
                extensions:
                  type: array
                  items:
                    type: string
        videoCaption:
          type: object
          properties:
            file:
              type: object
              properties:
                size:
                  type: object
                  properties:
                    max:
                      type: integer
                extensions:
                  type: array
                  items:
                    type: string
        user:
          type: object
          properties:
            videoQuota:
              type: integer
              description: In bytes
              example: 16810141515
            videoQuotaDaily:
              type: integer
              description: In bytes
              example: 1681014151
        trending:
          type: object
          properties:
            videos:
              type: object
              properties:
                intervalDays:
                  type: integer
        tracker:
          type: object
          properties:
            enabled:
              type: boolean
        followings:
          type: object
          properties:
            instance:
              type: object
              properties:
                autoFollowIndex:
                  type: object
                  properties:
                    indexUrl:
                      type: string
                      format: url
        federation:
          type: object
          properties:
            enabled:
              type: boolean
        homepage:
          type: object
          properties:
            enabled:
              type: boolean

        openTelemetry:
          type: object
          description: 'PeerTube >= 6.1'
          properties:
            metrics:
              type: object
              properties:
                enabled:
                  type: boolean
                playbackStatsInterval:
                  type: number
                  description: 'Milliseconds'

        views:
          type: object
          description: 'PeerTube >= 6.1'
          properties:
            videos:
              type: object
              properties:
                countViewAfter:
                  type: number
                  description: 'Milliseconds'
                watchingInterval:
                  type: object
                  properties:
                    anonymous:
                      type: number
                      description: 'Milliseconds'
                    users:
                      type: number
                      description: 'Milliseconds'

    SendClientLog:
      properties:
        message:
          type: string
        url:
          type: string
          description: URL of the current user page
        level:
          enum:
            - error
            - warn
        stackTrace:
          type: string
          description: Stack trace of the error if there is one
        userAgent:
          type: string
          description: User agent of the web browser that sends the message
        meta:
          type: string
          description: Additional information regarding this log
      required:
        - message
        - url
        - level

    ServerStats:
      properties:
        totalUsers:
          type: number
        totalDailyActiveUsers:
          type: number
        totalWeeklyActiveUsers:
          type: number
        totalMonthlyActiveUsers:
          type: number
        totalModerators:
          type: number
          description: "**PeerTube >= 6.1** Value is null if the admin disabled total moderators stats"
        totalAdmins:
          type: number
          description: "**PeerTube >= 6.1** Value is null if the admin disabled total admins stats"
        totalLocalVideos:
          type: number
        totalLocalVideoViews:
          type: number
          description: Total video views made on the instance
        totalLocalVideoDownloads:
          type: number
          description: Total video downloads made on the instance
        totalLocalVideoComments:
          type: number
          description: Total comments made by local users
        totalLocalVideoFilesSize:
          type: number
        totalVideos:
          type: number
        totalVideoComments:
          type: number
        totalLocalVideoChannels:
          type: number
        totalLocalDailyActiveVideoChannels:
          type: number
        totalLocalWeeklyActiveVideoChannels:
          type: number
        totalLocalMonthlyActiveVideoChannels:
          type: number
        totalLocalPlaylists:
          type: number
        totalInstanceFollowers:
          type: number
        totalInstanceFollowing:
          type: number
        videosRedundancy:
          type: array
          items:
            type: object
            properties:
                strategy:
                  type: string
                totalSize:
                  type: number
                totalUsed:
                  type: number
                totalVideoFiles:
                  type: number
                totalVideos:
                  type: number
        totalActivityPubMessagesProcessed:
          type: number
        totalActivityPubMessagesSuccesses:
          type: number
        totalActivityPubMessagesErrors:
          type: number

        activityPubMessagesProcessedPerSecond:
          type: number
        totalActivityPubMessagesWaiting:
          type: number

        averageRegistrationRequestResponseTimeMs:
          type: number
          description: "**PeerTube >= 6.1** Value is null if the admin disabled registration requests stats"
        totalRegistrationRequestsProcessed:
          type: number
          description: "**PeerTube >= 6.1** Value is null if the admin disabled registration requests stats"
        totalRegistrationRequests:
          type: number
          description: "**PeerTube >= 6.1** Value is null if the admin disabled registration requests stats"

        averageAbuseResponseTimeMs:
          type: number
          description: "**PeerTube >= 6.1** Value is null if the admin disabled abuses stats"
        totalAbusesProcessed:
          type: number
          description: "**PeerTube >= 6.1** Value is null if the admin disabled abuses stats"
        totalAbuses:
          type: number
          description: "**PeerTube >= 6.1** Value is null if the admin disabled abuses stats"

    ServerConfigAbout:
      properties:
        instance:
          type: object
          properties:
            name:
              type: string
            shortDescription:
              type: string
            description:
              type: string
            terms:
              type: string
            codeOfConduct:
              type: string
            hardwareInformation:
              type: string
            creationReason:
              type: string
            moderationInformation:
              type: string
            administrator:
              type: string
            maintenanceLifetime:
              type: string
            businessModel:
              type: string
            support:
              type: object
              properties:
                text:
                  type: string
            languages:
              type: array
              items:
                  type: string
            categories:
              type: array
              items:
                type: integer
            avatars:
              type: array
              items:
                $ref: '#/components/schemas/ActorImage'
            banners:
              type: array
              items:
                $ref: '#/components/schemas/ActorImage'
    InstanceTranslation:
      properties:
        language:
          type: string
          description: Locale of the web interface
          example: fr-FR
        shortDescription:
          type: string
        description:
          type: string
        terms:
          type: string
        codeOfConduct:
          type: string
        moderationInformation:
          type: string
        administrator:
          type: string
        creationReason:
          type: string
        maintenanceLifetime:
          type: string
        businessModel:
          type: string
        hardwareInformation:
          type: string
        supportText:
          type: string
    ServerConfigCustom:
      properties:
        instance:
          type: object
          properties:
            name:
              type: string
            shortDescription:
              type: string
            description:
              type: string
            terms:
              type: string
            codeOfConduct:
              type: string
            creationReason:
              type: string
            moderationInformation:
              type: string
            administrator:
              type: string
            maintenanceLifetime:
              type: string
            businessModel:
              type: string
            hardwareInformation:
              type: string
            translations:
              type: array
              description: Translations of the instance information. Empty fields fall back to the default instance information
              items:
                $ref: '#/components/schemas/InstanceTranslation'
            languages:
              type: array
              items:
                type: string
            categories:
              type: array
              items:
                type: number
            isNSFW:
              type: boolean
            defaultNSFWPolicy:
              type: string
            serverCountry:
              type: string
            support:
              type: object
              properties:
                text:
                  type: string
            social:
              type: object
              properties:
                externalLink:
                  type: string
                mastodonLink:
                  type: string
                blueskyLink:
                  type: string
                xLink:
                  type: string
            defaultClientRoute:
              type: string
            customizations:
              type: object
              properties:
                javascript:
                  type: string
                css:
                  type: string
        theme:
          type: object
          properties:
            default:
              type: string
        services:
          type: object
          properties:
            twitter:
              type: object
              properties:
                username:
                  type: string
        cache:
          type: object
          properties:
            previews:
              type: object
              properties:
                size:
                  type: integer
            captions:
              type: object
              properties:
                size:
                  type: integer
        signup:
          type: object
          properties:
            enabled:
              type: boolean
            limit:
              type: integer
            requiresEmailVerification:
              type: boolean
        admin:
          type: object
          properties:
            email:
              type: string
              format: email
        contactForm:
          type: object
          properties:
            enabled:
              type: boolean
        user:
          type: object
          description: Settings that apply to new users, if registration is enabled
          properties:
            videoQuota:
              type: integer
              example: 16810141515
            videoQuotaDaily:
              type: integer
              example: 1681014151
        transcoding:
          type: object
          description: Settings pertaining to transcoding jobs
          properties:
            enabled:
              type: boolean
            originalFile:
              type: object
              properties:
                keep:
                  type: boolean
            allowAdditionalExtensions:
              type: boolean
              description: Allow your users to upload .mkv, .mov, .avi, .wmv, .flv, .f4v, .3g2, .3gp, .mts, m2ts, .mxf, .nut videos
            allowAudioFiles:
              type: boolean
              description: If a user uploads an audio file, PeerTube will create a video by merging the preview file and the audio file
            threads:
              type: integer
              description: Amount of threads used by ffmpeg for 1 transcoding job
            concurrency:
              type: number
              description: Amount of transcoding jobs to execute in parallel
            profile:
              type: string
              enum:
                - default
              description: |
                New profiles can be added by plugins ; available in core PeerTube: 'default'.
            resolutions:
              type: object
              description: Resolutions to transcode _new videos_ to
              properties:
                0p:
                  type: boolean
                144p:
                  type: boolean
                240p:
                  type: boolean
                360p:
                  type: boolean
                480p:
                  type: boolean
                720p:
                  type: boolean
                1080p:
                  type: boolean
                1440p:
                  type: boolean
                2160p:
                  type: boolean
            web_videos:
              type: object
              description: Web Video specific settings
              properties:
                enabled:
                  type: boolean
            hls:
              type: object
              description: HLS specific settings
              properties:
                enabled:
                  type: boolean
                splitAudioAndVideo:
                  type: boolean
        import:
          type: object
          properties:
            videos:
              type: object
              properties:
                http:
                  type: object
                  properties:
                    enabled:
                      type: boolean
                torrent:
                  type: object
                  properties:
                    enabled:
                      type: boolean
            video_channel_synchronization:
              type: object
              properties:
                enabled:
                  type: boolean
        autoBlacklist:
          type: object
          properties:
            videos:
              type: object
              properties:
                ofUsers:
                  type: object
                  properties:
                    enabled:
                      type: boolean
        blocklist:
          type: object
          properties:
            publicLog:
              type: object
              properties:
                enabled:
                  type: boolean
        followers:
          type: object
          properties:
            instance:
              type: object
              properties:
                enabled:
                  type: boolean
                manualApproval:
                  type: boolean
        storyboard:
          type: object
          properties:
            enabled:
              type: boolean
        defaults:
          type: object
          properties:
            publish:
              type: object
              properties:
                downloadEnabled:
                  type: boolean
                commentsPolicy:
                  $ref: '#/components/schemas/VideoCommentsPolicySet'
                recommendationScope:
                  $ref: '#/components/schemas/VideoRecommendationScopeSet'
                privacy:
                  $ref: '#/components/schemas/VideoPrivacySet'
                licence:
                  $ref: '#/components/schemas/VideoLicenceSet'
            p2p:
              type: object
              properties:
                webapp:
                  type: object
                  properties:
                    enabled:
                      type: boolean
                embed:
                  type: object
                  properties:
                    enabled:
                      type: boolean
            player:
              type: object
              properties:
                autoPlay:
                  type: boolean

    CustomHomepage:
      properties:
        content:
          type: string

    Follow:
      properties:
        id:
          $ref: '#/components/schemas/id'
        follower:
          $ref: '#/components/schemas/Actor'
        following:
          $ref: '#/components/schemas/Actor'
        score:
          type: number
          description: score reflecting the reachability of the actor, with steps of `10` and a base score of `1000`.
        state:
          type: string
          enum:
            - pending
            - accepted
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time

    PredefinedAbuseReasons:
      description: Reason categories that help triage reports
      type: array
      maxItems: 8
      items:
        type: string
        enum:
        - violentOrAbusive
        - hatefulOrAbusive
        - spamOrMisleading
        - privacy
        - rights
        - serverRules
        - thumbnails
        - captions

    JobType:
      type: string
      enum:
        - activitypub-cleaner
        - activitypub-follow
        - activitypub-http-broadcast
        - activitypub-http-broadcast-parallel
        - activitypub-http-fetcher
        - activitypub-http-unicast
        - activitypub-refresher
        - actor-keys
        - after-video-channel-import
        - build-automatic-tags
        - build-object-automatic-tags
        - create-user-export
        - email
        - federate-video
        - generate-video-storyboard
        - import-user-archive
        - manage-video-torrent
        - move-to-file-system
        - move-to-object-storage
        - notify
        - transcoding-job-builder
        - video-channel-import
        - video-file-import
        - video-files-lifecycle
        - video-import
        - video-live-ending
        - video-redundancy
        - video-studio-edition
        - video-transcoding
        - video-transcription
        - videos-stats

    Job:
      properties:
        id:
          $ref: '#/components/schemas/id'
        state:
          type: string
          enum:
            - active
            - completed
            - failed
            - waiting
            - delayed
        type:
          $ref: '#/components/schemas/JobType'
        data:
          type: object
          additionalProperties: true
        error:
          type: object
          additionalProperties: true
        createdAt:
          type: string
          format: date-time
        finishedOn:
          type: string
          format: date-time
        processedOn:
          type: string
          format: date-time
        canCancel:
          description: Whether this job is currently running and supports cancellation
          type: boolean
    AddUserResponse:
      properties:
        user:
          type: object
          properties:
            id:
              $ref: '#/components/schemas/id'
            account:
              type: object
              properties:
                id:
                  $ref: '#/components/schemas/id'

    VideoUploadRequestCommon:
      properties:
        name:
          description: Video name
          type: string
          example: What is PeerTube?
          minLength: 3
          maxLength: 120
        channelId:
          description: Channel id that will contain this video
          type: integer
          example: 3
          minimum: 1
        privacy:
          $ref: '#/components/schemas/VideoPrivacySet'
        category:
          $ref: '#/components/schemas/VideoCategorySet'
        licence:
          $ref: '#/components/schemas/VideoLicenceSet'
        language:
          $ref: '#/components/schemas/VideoLanguageSet'
        description:
          description: Video description
          type: string
          example: |
            **[Want to help to translate this video?](https://weblate.framasoft.org/projects/what-is-peertube-video/)**\r\n\r\n**Take back the control of your videos! [#JoinPeertube](https://joinpeertube.org)**
        waitTranscoding:
          description: Whether or not we wait transcoding before publish the video
          type: boolean
        generateTranscription:
          description: "**PeerTube >= 6.2** If enabled by the admin, automatically generate a subtitle of the video"
          type: boolean
        support:
          description: A text tell the audience how to support the video creator
          example: Please support our work on https://soutenir.framasoft.org/en/ <3
          type: string
        nsfw:
          description: Whether or not this video contains sensitive content
          type: boolean
        nsfwSummary:
            description: More information about the sensitive content of the video
        nsfwFlags:
          $ref: '#/components/schemas/NSFWFlag'
        tags:
          description: Video tags (maximum 5 tags each between 2 and 30 characters)
          type: array
          minItems: 1
          maxItems: 5
          uniqueItems: true
          example:
            - framasoft
            - peertube
          items:
            type: string
            minLength: 2
            maxLength: 30
        commentsPolicy:
          $ref: '#/components/schemas/VideoCommentsPolicySet'
        recommendationScope:
          $ref: '#/components/schemas/VideoRecommendationScopeSet'
        aiUsage:
          $ref: '#/components/schemas/VideoAIUsageSet'
        commercialContent:
          $ref: '#/components/schemas/VideoCommercialContentSet'
        downloadEnabled:
          description: Enable or disable downloading for this video
          type: boolean
        originallyPublishedAt:
          description: Date when the content was originally published
          type: string
          format: date-time
        scheduleUpdate:
          $ref: '#/components/schemas/VideoScheduledUpdate'
        thumbnailfile:
          description: Video thumbnail file
          type: string
          format: binary
        previewfile:
          description: Deprecated in PeerTube v8.1, use thumbnailfile instead
          deprecated: true
          type: string
          format: binary
        videoPasswords:
          $ref: '#/components/schemas/AddVideoPasswords'
      required:
        - channelId
        - name
    VideoUploadRequestLegacy:
      allOf:
        - $ref: '#/components/schemas/VideoUploadRequestCommon'
        - type: object
          required:
            - videofile
          properties:
            videofile:
              description: Video file
              type: string
              format: binary
    VideoUploadRequestResumable:
      allOf:
        - $ref: '#/components/schemas/VideoUploadRequestCommon'
        - type: object
          required:
            - filename
          properties:
            filename:
              description: Video filename including extension
              type: string
              format: filename
              example: what_is_peertube.mp4
            thumbnailfile:
              description: Video thumbnail file
              type: string
              format: binary
            previewfile:
              description: Deprecated in PeerTube v8.1, use thumbnailfile instead
              deprecated: true
              type: string
              format: binary
    VideoUploadResponse:
      properties:
        video:
          type: object
          properties:
            id:
              $ref: '#/components/schemas/Video/properties/id'
            uuid:
              $ref: '#/components/schemas/Video/properties/uuid'
            shortUUID:
              $ref: '#/components/schemas/Video/properties/shortUUID'
    VideoReplaceSourceRequestResumable:
      properties:
        filename:
          description: Video filename including extension
          type: string
          format: filename
          example: what_is_peertube.mp4
    UserImportResumable:
      properties:
        filename:
          description: Archive filename including extension
          type: string
          format: filename
          example: "user-export-6-2024-02-09T10_12_11.682Z"
    CommentThreadResponse:
      properties:
        total:
          type: integer
          description: Total threads (included deleted ones) on this video
        totalNotDeletedComments:
          type: integer
          description: Total not-deleted threads (included deleted ones) on this video
        data:
          type: array
          maxItems: 100
          items:
            $ref: '#/components/schemas/VideoComment'
    CommentThreadPostResponse:
      properties:
        comment:
          $ref: '#/components/schemas/VideoComment'
    VideoTokenResponse:
      properties:
        files:
          type: object
          properties:
            token:
              type: string
            expires:
              type: string
              format: date-time
    VideoListResponse:
      properties:
        total:
          type: integer
          example: 1
        data:
          type: array
          maxItems: 100
          items:
            $ref: '#/components/schemas/Video'

    ChannelActivityListResponse:
      properties:
        total:
          type: integer
          example: 1
        data:
          type: array
          items:
            type: object
            properties:
              id:
                type: integer
              account:
                nullable: true
                description: The account may have been deleted
                $ref: '#/components/schemas/AccountSummary'
              action:
                type: object
                properties:
                  id:
                    $ref: '#/components/schemas/VideoChannelActivityAction'
                  label:
                    type: string
              targetType:
                type: object
                properties:
                  id:
                    $ref: '#/components/schemas/VideoChannelActivityTarget'
                  label:
                    type: string
              details:
                type: object
                additionalProperties: true
              createdAt:
                type: string
                format: date-time
              channel:
                type: object
                properties:
                  id:
                    $ref: '#/components/schemas/id'
                  name:
                    type: string
                  displayName:
                    type: string
                  url:
                    type: string
                    format: url
              video:
                nullable: true
                type: object
                properties:
                  id:
                    $ref: '#/components/schemas/id'
                  name:
                    type: string
                  uuid:
                    $ref: '#/components/schemas/UUIDv4'
                  shortUUID:
                    $ref: '#/components/schemas/shortUUID'
                  url:
                    type: string
                    format: url
                  isLive:
                    type: boolean
              videoImport:
                nullable: true
                type: object
                properties:
                  id:
                    $ref: '#/components/schemas/id'
                  name:
                    type: string
                  uuid:
                    $ref: '#/components/schemas/UUIDv4'
                  shortUUID:
                    $ref: '#/components/schemas/shortUUID'
                  url:
                    type: string
                    format: url
                  targetUrl:
                    type: string
                    format: uri
              playlist:
                nullable: true
                type: object
                properties:
                  id:
                    $ref: '#/components/schemas/id'
                  name:
                    type: string
                  uuid:
                    $ref: '#/components/schemas/UUIDv4'
                  shortUUID:
                    $ref: '#/components/schemas/shortUUID'
                  url:
                    type: string
                    format: url
              channelSync:
                nullable: true
                type: object
                properties:
                  id:
                    $ref: '#/components/schemas/id'
                  externalChannelUrl:
                    type: string
                    format: uri

    UserNotificationSettings:
      properties:
        abuseAsModerator:
          $ref: '#/components/schemas/NotificationSettingValue'
        videoAutoBlacklistAsModerator:
          $ref: '#/components/schemas/NotificationSettingValue'
        newUserRegistration:
          $ref: '#/components/schemas/NotificationSettingValue'

        newVideoFromSubscription:
          $ref: '#/components/schemas/NotificationSettingValue'

        blacklistOnMyVideo:
          $ref: '#/components/schemas/NotificationSettingValue'
        myVideoPublished:
          $ref: '#/components/schemas/NotificationSettingValue'
        myVideoImportFinished:
          $ref: '#/components/schemas/NotificationSettingValue'

        commentMention:
          $ref: '#/components/schemas/NotificationSettingValue'
        newCommentOnMyVideo:
          $ref: '#/components/schemas/NotificationSettingValue'

        newFollow:
          $ref: '#/components/schemas/NotificationSettingValue'
        newInstanceFollower:
          $ref: '#/components/schemas/NotificationSettingValue'
        autoInstanceFollowing:
          $ref: '#/components/schemas/NotificationSettingValue'

        abuseStateChange:
          $ref: '#/components/schemas/NotificationSettingValue'
        abuseNewMessage:
          $ref: '#/components/schemas/NotificationSettingValue'

        newPeerTubeVersion:
          $ref: '#/components/schemas/NotificationSettingValue'
        newPluginVersion:
          $ref: '#/components/schemas/NotificationSettingValue'

        myVideoStudioEditionFinished:
          $ref: '#/components/schemas/NotificationSettingValue'

        myVideoTranscriptionGenerated:
          $ref: '#/components/schemas/NotificationSettingValue'

    User:
      properties:
        id:
          $ref: '#/components/schemas/id'
        username:
          $ref: '#/components/schemas/username'
        email:
          type: string
          format: email
          description: The user email
        emailVerified:
          type: boolean
          description: Has the user confirmed their email address?

        nsfwPolicy:
          $ref: '#/components/schemas/NSFWPolicy'
        nsfwFlagsDisplayed:
          $ref: '#/components/schemas/NSFWFlag'
        nsfwFlagsHidden:
          $ref: '#/components/schemas/NSFWFlag'
        nsfwFlagsWarned:
          $ref: '#/components/schemas/NSFWFlag'
        nsfwFlagsBlurred:
          $ref: '#/components/schemas/NSFWFlag'
        aiUsagesHidden:
          type: array
          description: "**PeerTube >= 9.0** Videos with these AI usages are hidden from video lists"
          items:
            $ref: '#/components/schemas/VideoAIUsageSet'

        adminFlags:
          $ref: '#/components/schemas/UserAdminFlags'

        autoPlayNextVideo:
          type: boolean
          description: Automatically start playing the upcoming video after the currently playing video
        autoPlayNextVideoPlaylist:
          type: boolean
          description: Automatically start playing the video on the playlist after the currently playing video
        autoPlayVideo:
          type: boolean
          description: Automatically start playing the video on the watch page

        p2pEnabled:
          type: boolean
          description: whether to enable P2P in the player or not

        videosHistoryEnabled:
          type: boolean
          description: whether to keep track of watched history or not
        videoLanguages:
          type: array
          items:
            type: string
          description: list of languages to filter videos down to
        videoCategories:
          type: array
          items:
            type: integer
          nullable: true
          description: list of categories to filter videos down to (`null` means all categories)
        videoLive:
          type: string
          enum:
            - 'true'
            - 'false'
            - both
          description: filter videos down to lives (`true`), VODs (`false`) or display both
        language:
          type: string
          description: default language for this user

        videoQuota:
          type: integer
          description: The user video quota in bytes
          example: -1
        videoQuotaDaily:
          type: integer
          description: The user daily video quota in bytes
          example: -1

        role:
          type: object
          properties:
            id:
              $ref: '#/components/schemas/UserRole'
            label:
              type: string
              enum:
                - User
                - Moderator
                - Administrator

        theme:
          type: string
          description: Theme enabled by this user

        account:
          $ref: '#/components/schemas/Account'

        notificationSettings:
          $ref: '#/components/schemas/UserNotificationSettings'

        videoChannels:
          type: array
          items:
            $ref: '#/components/schemas/VideoChannel'

        blocked:
          type: boolean
        blockedReason:
          type: string

        noInstanceConfigWarningModal:
          type: boolean
        noAccountSetupWarningModal:
          type: boolean
        noWelcomeModal:
          type: boolean

        createdAt:
          type: string

        pluginAuth:
          type: string
          description: Auth plugin to use to authenticate the user

        lastLoginDate:
          type: string
          format: date-time

        twoFactorEnabled:
          type: boolean
          description: Whether the user has enabled two-factor authentication or not

        newFeaturesInfoRead:
          type: number
          description: New features information the user has read

    UserWithStats:
      allOf:
        - $ref: '#/components/schemas/User'
        - properties:
            # optionally present fields: they require WITH_STATS scope
            videosCount:
              type: integer
              description: Count of videos published
            abusesCount:
              type: integer
              description: Count of reports/abuses of which the user is a target
            abusesAcceptedCount:
              type: integer
              description: Count of reports/abuses created by the user and accepted/acted upon by the moderation team
            abusesCreatedCount:
              type: integer
              description: Count of reports/abuses created by the user
            videoCommentsCount:
              type: integer
              description: Count of comments published
    AddUser:
      properties:
        username:
          $ref: '#/components/schemas/username'
        password:
          $ref: '#/components/schemas/password'
        email:
          type: string
          format: email
          description: The user email
        videoQuota:
          type: integer
          description: The user video quota in bytes
          example: -1
        videoQuotaDaily:
          type: integer
          description: The user daily video quota in bytes
          example: -1
        channelName:
          $ref: '#/components/schemas/usernameChannel'
        role:
          $ref: '#/components/schemas/UserRole'
        adminFlags:
          $ref: '#/components/schemas/UserAdminFlags'
        currentPassword:
          description: Required to create an administrator, see [password confirmation](#section/Password-confirmation)
          allOf:
            - $ref: '#/components/schemas/currentPassword'
      required:
        - username
        - password
        - email
        - role
    UpdateUser:
      properties:
        email:
          description: The updated email of the user
          allOf:
            - $ref: '#/components/schemas/User/properties/email'
        emailVerified:
          type: boolean
          description: Set the email as verified
        videoQuota:
          type: integer
          description: The updated video quota of the user in bytes
        videoQuotaDaily:
          type: integer
          description: The updated daily video quota of the user in bytes
        pluginAuth:
          type: string
          nullable: true
          description: The auth plugin to use to authenticate the user
          example: 'peertube-plugin-auth-saml2'
        role:
          $ref: '#/components/schemas/UserRole'
        adminFlags:
          $ref: '#/components/schemas/UserAdminFlags'
        password:
          $ref: '#/components/schemas/password'
        currentPassword:
          description: >
            Required to give the administrator role, or to change the password, email or auth plugin of an administrator, see [password confirmation](#section/Password-confirmation)
          allOf:
            - $ref: '#/components/schemas/currentPassword'
    UpdateMe:
      properties:
        password:
          $ref: '#/components/schemas/password'
        currentPassword:
          $ref: '#/components/schemas/password'
        email:
          description: new email used for login and service communications
          allOf:
            - $ref: '#/components/schemas/User/properties/email'
        displayName:
          type: string
          description: new name of the user in its representations
          minLength: 3
          maxLength: 120
        nsfwPolicy:
          type: string
          description: new NSFW display policy
          enum:
            - 'true'
            - 'false'
            - both
        nsfwFlagsDisplayed:
          $ref: '#/components/schemas/NSFWFlag'
        nsfwFlagsHidden:
          $ref: '#/components/schemas/NSFWFlag'
        nsfwFlagsWarned:
          $ref: '#/components/schemas/NSFWFlag'
        nsfwFlagsBlurred:
          $ref: '#/components/schemas/NSFWFlag'
        aiUsagesHidden:
          type: array
          description: "**PeerTube >= 9.0** Videos with these AI usages are hidden from video lists"
          items:
            $ref: '#/components/schemas/VideoAIUsageSet'
        p2pEnabled:
          type: boolean
          description: whether to enable P2P in the player or not
        autoPlayVideo:
          type: boolean
          description: new preference regarding playing videos automatically
        autoPlayNextVideo:
          type: boolean
          description: new preference regarding playing following videos automatically
        autoPlayNextVideoPlaylist:
          type: boolean
          description: new preference regarding playing following playlist videos automatically
        videosHistoryEnabled:
          type: boolean
          description: whether to keep track of watched history or not
        videoLanguages:
          type: array
          items:
            type: string
          description: list of languages to filter videos down to
        videoCategories:
          type: array
          items:
            type: integer
          nullable: true
          description: list of categories to filter videos down to (`null` means all categories)
        videoLive:
          type: string
          enum:
            - 'true'
            - 'false'
            - both
          description: filter videos down to lives (`true`), VODs (`false`) or display both
        language:
          type: string
          description: default language for this user
        theme:
          type: string
        noInstanceConfigWarningModal:
          type: boolean
        noAccountSetupWarningModal:
          type: boolean
        noWelcomeModal:
          type: boolean
    GetMeVideoRating:
      properties:
        id:
          $ref: '#/components/schemas/id'
        rating:
          type: string
          enum:
            - like
            - dislike
            - none
          description: Rating of the video
      required:
        - id
        - rating
    VideoRating:
      properties:
        video:
          $ref: '#/components/schemas/Video'
        rating:
          type: string
          enum:
            - like
            - dislike
            - none
          description: Rating of the video
      required:
        - video
        - rating

    RegisterUser:
      properties:
        username:
          description: immutable name of the user, used to find or mention its actor
          allOf:
            - $ref: '#/components/schemas/username'
        password:
          $ref: '#/components/schemas/password'
        email:
          type: string
          format: email
          description: email of the user, used for login or service communications
        displayName:
          type: string
          description: editable name of the user, displayed in its representations
          minLength: 1
          maxLength: 120
        channel:
          type: object
          description: channel base information used to create the first channel of the user
          properties:
            name:
              $ref: '#/components/schemas/usernameChannel'
            displayName:
              type: string
        signupClient:
          type: string
          enum:
            - peertube-app
          description: |
            **PeerTube >= 9.0** Client used to sign up. If set, links of the verification and registration accepted emails
            make the web client propose to open this client
      required:
        - username
        - password
        - email

    UserRegistrationRequest:
      allOf:
        - $ref: '#/components/schemas/RegisterUser'
        - type: object
          properties:
            registrationReason:
              type: string
              description: reason for the user to register on the instance
          required:
            - registrationReason

    UserRegistrationAcceptOrReject:
      type: object
      properties:
        moderationResponse:
          type: string
          description: Moderation response to send to the user
        preventEmailDelivery:
          type: boolean
          description: Set it to true if you don't want PeerTube to send an email to the user
      required:
        - moderationResponse

    AuditLogAction:
      type: string
      enum:
        - create
        - update
        - delete

    AuditLogEntityType:
      type: string
      enum:
        - video
        - video-import
        - video-live
        - video-source
        - video-file
        - video-caption
        - video-chapters
        - video-password
        - video-embed-privacy
        - video-transcoding
        - video-transcription
        - video-studio-edition
        - video-player-settings
        - ownership-change
        - comment
        - channel
        - channel-sync
        - channel-videos-import
        - channel-collaborator
        - channel-player-settings
        - channel-playlists-order
        - playlist
        - playlist-element
        - playlist-elements-order
        - user
        - registration
        - password-reset
        - token-session
        - failed-login
        - scoped-token
        - user-export
        - user-import
        - abuse
        - abuse-message
        - video-block
        - account-block
        - server-block
        - blocklist-subscription
        - watched-words-list
        - watched-words-subscription
        - automatic-tag-policy
        - config
        - instance-image
        - instance-homepage
        - instance-host
        - plugin
        - follow
        - server-redundancy
        - video-redundancy
        - job-queue
        - job
        - runner
        - runner-registration-token
        - debug-command
        - storage-prune

    AuditLog:
      type: object
      properties:
        id:
          $ref: '#/components/schemas/id'
        action:
          $ref: '#/components/schemas/AuditLogAction'
        entityType:
          $ref: '#/components/schemas/AuditLogEntityType'
        entityId:
          type: integer
          nullable: true
          description: Id of the audited entity, `null` for the instance configuration
        user:
          type: object
          properties:
            id:
              type: integer
              nullable: true
              description: '`null` if the user has been deleted, for remote actors or for entries imported from the legacy audit log files'
            username:
              type: string
              description: Username at the time of the action, or the actor handle for remote actors
        ip:
          type: string
          nullable: true
          description: IP address of the request, anonymized if `log.anonymize_ip` is enabled
        entity:
          type: object
          additionalProperties: true
          description: Snapshot of the entity after the action (before the action for deletions)
        changes:
          type: object
          nullable: true
          description: Only for updates. Keys are dot-separated paths of the changed entity attributes
          additionalProperties:
            type: object
            properties:
              old: {}
              new: {}
        createdAt:
          type: string
          format: date-time
        timestamp:
          type: string
          format: date-time
          deprecated: true
          description: Same as `createdAt`. Field of the format used before audit logs were stored in the database
        level:
          type: string
          deprecated: true
          enum:
            - audit
          description: Field of the format used before audit logs were stored in the database
        message:
          type: string
          deprecated: true
          description: |
            JSON string containing the `user`, `domain` (entity type), `action`, `entityId`, `ip` and `changes` of the entry, and the properties of the audited entity.
            Field of the format used before audit logs were stored in the database

    UserRegistrationState:
      type: integer
      enum:
        - 1
        - 2
        - 3
      description: 'The registration state (Pending = `1`, Rejected = `2`, Accepted = `3`)'

    ChangeOwnershipState:
      type: integer
      enum:
        - 1
        - 2
        - 3
      description: 'The ownership change state (Pending = `1`, Rejected = `2`, Accepted = `3`)'

    UserRegistration:
      properties:
        id:
          $ref: '#/components/schemas/id'
        state:
          type: object
          properties:
            id:
              $ref: '#/components/schemas/UserRegistrationState'
            label:
              type: string
        registrationReason:
          type: string
        moderationResponse:
          type: string
          nullable: true
        username:
          type: string
        email:
          type: string
          format: email
        emailVerified:
          type: boolean
        accountDisplayName:
          type: string
        channelHandle:
          type: string
        channelDisplayName:
          type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        user:
          type: object
          nullable: true
          description: If the registration has been accepted, this is a partial user object created by the registration
          properties:
            id:
              $ref: '#/components/schemas/id'

    OAuthClient:
      properties:
        client_id:
          type: string
          pattern: /^[a-z0-9]$/
          maxLength: 32
          minLength: 32
          example: v1ikx5hnfop4mdpnci8nsqh93c45rldf
        client_secret:
          type: string
          pattern: /^[a-zA-Z0-9]$/
          maxLength: 32
          minLength: 32
          example: AjWiOapPltI6EnsWQwlFarRtLh4u8tDt
    OAuthToken-password:
      allOf:
        - $ref: '#/components/schemas/OAuthClient'
        - type: object
          properties:
            grant_type:
              type: string
              enum:
                - password
            username:
              $ref: '#/components/schemas/User/properties/username'
            password:
              $ref: '#/components/schemas/password'
            externalAuthToken:
              type: string
              description: If you want to authenticate using an external authentication token you got from an auth plugin (like `peertube-plugin-auth-openid-connect` for example) instead of a password or a refresh token, provide it here.
      required:
        - client_id
        - client_secret
        - grant_type
        - username
    OAuthToken-refresh_token:
      allOf:
        - $ref: '#/components/schemas/OAuthClient'
        - type: object
          properties:
            grant_type:
              type: string
              enum:
                - refresh_token
            refresh_token:
              type: string
              example: 2e0d675df9fc96d2e4ec8a3ebbbf45eca9137bb7
      required:
        - client_id
        - client_secret
        - grant_type
        - refresh_token

    VideoChannel:
      allOf:
        - $ref: '#/components/schemas/Actor'
        - type: object
          properties:
            displayName:
              type: string
              description: editable name of the channel, displayed in its representations
              example: Videos of Framasoft
              minLength: 1
              maxLength: 120
            description:
              type: string
              nullable: true
              example: Videos made with <3 by Framasoft
              minLength: 3
              maxLength: 1000
            support:
              type: string
              nullable: true
              description: text shown by default on all videos of this channel, to tell the audience how to support it
              example: Please support our work on https://soutenir.framasoft.org/en/ <3
              minLength: 3
              maxLength: 1000
            publicEmail:
              type: string
              format: email
              nullable: true
              description: Public email visible in podcast RSS feeds
            isLocal:
              type: boolean
            updatedAt:
              type: string
              format: date-time
            banners:
              type: array
              items:
                $ref: '#/components/schemas/ActorImage'
            ownerAccount:
              $ref: '#/components/schemas/Account'
            videosCount:
              type: integer
              description: only included when `withStats` is true
            viewsPerDay:
              type: array
              description: >
                only included when `withStats` is true. Chronologically ordered, spans the whole `statsDays`
                range. Each point aggregates `viewsGroupInterval` worth of views, starting at `date`
              items:
                type: object
                properties:
                  date:
                    type: string
                    format: date-time
                  views:
                    type: integer
            viewsGroupInterval:
              type: string
              description: bucket size of `viewsPerDay`, only included when `withStats` is true
              enum:
                - day
                - week
                - month
            totalViews:
              type: integer
              description: lifetime views of all the channel videos, only included when `withStats` is true

    VideoChannelEdit:
      properties:
        displayName:
          description: Channel display name
        description:
          description: Channel description
        support:
          description: How to support/fund the channel
        publicEmail:
          type: string
          format: email
          nullable: true
          description: Public email visible in podcast RSS feeds

    VideoChannelCreate:
      allOf:
        - $ref: '#/components/schemas/VideoChannelEdit'
        - properties:
            name:
              description: username of the channel to create
              allOf:
                - $ref: '#/components/schemas/usernameChannel'
      required:
        - name
        - displayName
    VideoChannelUpdate:
      allOf:
        - $ref: '#/components/schemas/VideoChannelEdit'
        - properties:
            bulkVideosSupportUpdate:
              type: boolean
              description: Update the support field for all videos of this channel

    VideoChannelList:
      properties:
        total:
          type: integer
          example: 1
        data:
          type: array
          items:
            allOf:
              - $ref: '#/components/schemas/VideoChannel'
              - $ref: '#/components/schemas/Actor'

    ImportVideosInChannelCreate:
      type: object
      properties:
        externalChannelUrl:
          type: string
          example: https://youtube.com/c/UC_myfancychannel
        videoChannelSyncId:
          type: integer
          description: If part of a channel sync process, specify its id to assign video imports to this channel synchronization
      required:
        - 'externalChannelUrl'

    VideoChannelSync:
      type: object
      properties:
        id:
          $ref: '#/components/schemas/id'
        state:
          type: object
          properties:
            id:
              type: integer
              example: 2
            label:
              type: string
              example: PROCESSING
        externalChannelUrl:
          type: string
          example: 'https://youtube.com/c/UC_myfancychannel'
        createdAt:
          type: string
          format: date-time
        lastSyncAt:
          type: string
          format: date-time
          nullable: true
        channel:
          $ref: '#/components/schemas/VideoChannel'
        videoPrivacy:
          type: integer
          nullable: true
          description: Default privacy of videos imported by this synchronization
    VideoChannelSyncList:
      type: object
      properties:
        total:
          type: integer
          example: 1
        data:
          type: array
          items:
            allOf:
              - $ref: '#/components/schemas/VideoChannelSync'
    VideoChannelSyncCreate:
      type: object
      properties:
        externalChannelUrl:
          type: string
          example: https://youtube.com/c/UC_myfancychannel
        videoChannelId:
          $ref: '#/components/schemas/id'
        videoPrivacy:
          type: integer
          description: |
            Privacy of imported videos (1 = PUBLIC, 2 = UNLISTED, 3 = PRIVATE, 4 = INTERNAL).
            Password protected privacy is not supported
    MRSSPeerLink:
      type: object
      xml:
        name: 'media:peerLink'
      properties:
        href:
          type: string
          xml:
            attribute: true
        type:
          type: string
          enum:
            - application/x-bittorrent
          xml:
            attribute: true
    MRSSGroupContent:
      type: object
      xml:
        name: 'media:content'
      properties:
        url:
          type: string
          format: url
          xml:
            attribute: true
        fileSize:
          type: integer
          xml:
            attribute: true
        type:
          type: string
          xml:
            attribute: true
        framerate:
          type: integer
          xml:
            attribute: true
        duration:
          type: integer
          xml:
            attribute: true
        height:
          type: integer
          xml:
            attribute: true
        lang:
          type: string
          xml:
            attribute: true
    VideoCommentsForXML:
      type: array
      xml:
        wrapped: true
        name: 'channel'
      items:
        type: object
        xml:
          name: 'item'
        properties:
          link:
            type: string
            format: url
          guid:
            type: string
          pubDate:
            type: string
            format: date-time
          'content:encoded':
            type: string
          'dc:creator':
            type: string
    VideosForXML:
      type: array
      xml:
        wrapped: true
        name: 'channel'
      items:
        type: object
        xml:
          name: 'item'
        properties:
          link:
            type: string
            format: url
            description: video watch page URL
          guid:
            type: string
            description: video canonical URL
          pubDate:
            type: string
            format: date-time
            description: video publication date
          description:
            type: string
            description: video description
          'content:encoded':
            type: string
            description: video description
          'dc:creator':
            type: string
            description: publisher user name
          'media:category':
            type: integer
            description: video category (MRSS)
          'media:community':
            type: object
            description: see [media:community](https://www.rssboard.org/media-rss#media-community) (MRSS)
            properties:
              'media:statistics':
                type: object
                properties:
                  views:
                    type: integer
                    xml:
                      attribute: true
          'media:embed':
            type: object
            properties:
              url:
                type: string
                format: url
                description: video embed path, relative to the canonical URL domain (MRSS)
                xml:
                  attribute: true
          'media:player':
            type: object
            properties:
              url:
                type: string
                format: url
                description: video watch path, relative to the canonical URL domain (MRSS)
                xml:
                  attribute: true
          'media:thumbnail':
            type: object
            properties:
              url:
                type: string
                format: url
                xml:
                  attribute: true
              height:
                type: integer
                xml:
                  attribute: true
              width:
                type: integer
                xml:
                  attribute: true
          'media:title':
            type: string
            description: see [media:title](https://www.rssboard.org/media-rss#media-title) (MRSS). We only use `plain` titles.
          'media:description':
            type: string
          'media:rating':
            type: string
            enum:
              - nonadult
              - adult
            description: see [media:rating](https://www.rssboard.org/media-rss#media-rating) (MRSS)
          'enclosure':
            type: object
            description: main streamable file for the video
            properties:
              url:
                type: string
                format: url
                xml:
                  attribute: true
              type:
                type: string
                enum:
                  - application/x-bittorrent
                xml:
                  attribute: true
              length:
                type: integer
                xml:
                  attribute: true
          'media:group':
            type: array
            description: list of streamable files for the video. see [media:peerLink](https://www.rssboard.org/media-rss#media-peerlink) and [media:content](https://www.rssboard.org/media-rss#media-content) or  (MRSS)
            items:
              anyOf:
                - $ref: '#/components/schemas/MRSSPeerLink'
                - $ref: '#/components/schemas/MRSSGroupContent'
    NotificationSettingValue:
      type: integer
      description: >
        Notification type. One of the following values, or a sum of multiple values:

        - `0` NONE

        - `1` WEB

        - `2` EMAIL
    NotificationType:
      type: integer
      enum:
        - 1
        - 2
        - 3
        - 4
        - 5
        - 6
        - 7
        - 8
        - 9
        - 10
        - 11
        - 12
        - 13
        - 14
        - 15
        - 16
        - 17
        - 18
        - 19
        - 20
        - 21
        - 22
        - 23
        - 24
        - 25
        - 26
        - 27
        - 28
        - 29
        - 30
        - 31
        - 32
        - 33
        - 34
      description: >
        Notification type. One of the following values:

          - `1` NEW_VIDEO_FROM_SUBSCRIPTION

          - `2` NEW_COMMENT_ON_MY_VIDEO

          - `3` NEW_ABUSE_FOR_MODERATORS

          - `4` BLACKLIST_ON_MY_VIDEO

          - `5` UNBLACKLIST_ON_MY_VIDEO

          - `6` MY_VIDEO_PUBLISHED

          - `7` MY_VIDEO_IMPORT_SUCCESS

          - `8` MY_VIDEO_IMPORT_ERROR

          - `9` NEW_USER_REGISTRATION

          - `10` NEW_FOLLOW

          - `11` COMMENT_MENTION

          - `12` VIDEO_AUTO_BLACKLIST_FOR_MODERATORS

          - `13` NEW_INSTANCE_FOLLOWER

          - `14` AUTO_INSTANCE_FOLLOWING

          - `15` ABUSE_STATE_CHANGE

          - `16` ABUSE_NEW_MESSAGE

          - `17` NEW_PLUGIN_VERSION

          - `18` NEW_PEERTUBE_VERSION

          - `19` MY_VIDEO_STUDIO_EDITION_FINISHED

          - `20` NEW_USER_REGISTRATION_REQUEST

          - `21` NEW_LIVE_FROM_SUBSCRIPTION

          - `22` MY_VIDEO_TRANSCRIPTION_GENERATED

          - `23` INVITED_TO_COLLABORATE_TO_CHANNEL

          - `24` ACCEPTED_TO_COLLABORATE_TO_CHANNEL

          - `25` REFUSED_TO_COLLABORATE_TO_CHANNEL

          - `26` VIDEO_OWNERSHIP_CHANGED_REQUEST

          - `27` VIDEO_OWNERSHIP_CHANGED_ACCEPTED

          - `28` VIDEO_OWNERSHIP_CHANGED_REJECTED

          - `29` CHANNEL_OWNERSHIP_CHANGED_REQUEST

          - `30` CHANNEL_OWNERSHIP_CHANGED_ACCEPTED

          - `31` CHANNEL_OWNERSHIP_CHANGED_REJECTED

          - `32` AUTOMATIC_BLOCKLIST_UPDATE

          - `33` MY_VIDEO_STUDIO_EDITION_ERROR

          - `34` MY_VIDEO_DUPLICATION_ERROR

    NewFeatureInfoType:
      type: integer
      enum:
        - 1
      description: >
        Represent a new feature that can be displayed to inform users. One of the following values:

          - `1` CHANNEL_COLLABORATION

    Notification:
      properties:
        id:
          $ref: '#/components/schemas/id'
        type:
          $ref: '#/components/schemas/NotificationType'
        read:
          type: boolean
        video:
          nullable: true
          allOf:
            - $ref: '#/components/schemas/VideoInfo'
            - type: object
              properties:
                channel:
                  $ref: '#/components/schemas/ActorInfo'
        videoImport:
          nullable: true
          type: object
          properties:
            id:
              $ref: '#/components/schemas/id'
            video:
              nullable: true
              allOf:
                - $ref: '#/components/schemas/VideoInfo'
            torrentName:
              type: string
              nullable: true
            magnetUri:
              $ref: '#/components/schemas/VideoImport/properties/magnetUri'
            targetUri:
              type: string
              format: uri
              nullable: true
        comment:
          nullable: true
          type: object
          properties:
            id:
              $ref: '#/components/schemas/id'
            threadId:
              type: integer
            video:
              $ref: '#/components/schemas/VideoInfo'
            account:
              $ref: '#/components/schemas/ActorInfo'
            heldForReview:
              type: boolean
        videoAbuse:
          nullable: true
          type: object
          properties:
            id:
              $ref: '#/components/schemas/id'
            video:
              allOf:
                - $ref: '#/components/schemas/VideoInfo'
        videoBlacklist:
          nullable: true
          type: object
          properties:
            id:
              $ref: '#/components/schemas/id'
            video:
              allOf:
                - $ref: '#/components/schemas/VideoInfo'
        account:
          nullable: true
          allOf:
            - $ref: '#/components/schemas/ActorInfo'
        actorFollow:
          type: object
          nullable: true
          properties:
            id:
              $ref: '#/components/schemas/id'
            follower:
              $ref: '#/components/schemas/ActorInfo'
            state:
              type: string
              enum:
                - pending
                - accepted
            following:
              type: object
              properties:
                type:
                  type: string
                  enum:
                    - account
                    - channel
                    - instance
                name:
                  type: string
                displayName:
                  type: string
                host:
                  type: string
                  format: hostname
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
    NotificationListResponse:
      properties:
        total:
          type: integer
          example: 1
        data:
          type: array
          maxItems: 100
          items:
            $ref: '#/components/schemas/Notification'
    Plugin:
      properties:
        name:
          type: string
          example: peertube-plugin-auth-ldap
        type:
          type: integer
          description: >
            - `1`: PLUGIN

            - `2`: THEME
          enum:
            - 1
            - 2
        latestVersion:
          type: string
          example: 0.0.3
        version:
          type: string
          example: 0.0.1
        enabled:
          type: boolean
        uninstalled:
          type: boolean
        peertubeEngine:
          type: string
          example: 2.2.0
        description:
          type: string
        homepage:
          type: string
          format: url
          example: https://framagit.org/framasoft/peertube/official-plugins/tree/master/peertube-plugin-auth-ldap
        settings:
          type: object
          additionalProperties: true
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
    PluginResponse:
      properties:
        total:
          type: integer
          example: 1
        data:
          type: array
          maxItems: 100
          items:
            $ref: '#/components/schemas/Plugin'

    LiveVideoUpdate:
      properties:
        saveReplay:
          type: boolean
        replaySettings:
          $ref: '#/components/schemas/LiveVideoReplaySettings'
        permanentLive:
          description: User can stream multiple times in a permanent live
          type: boolean
        latencyMode:
          description: User can select live latency mode if enabled by the instance
          allOf:
            - $ref: '#/components/schemas/LiveVideoLatencyMode'
        schedules:
          type: array
          items:
            $ref: '#/components/schemas/LiveSchedule'

    LiveVideoResponse:
      properties:
        rtmpUrl:
          type: string
          description: Included in the response if an appropriate token is provided
        rtmpsUrl:
          type: string
          description: Included in the response if an appropriate token is provided
        streamKey:
          type: string
          description: RTMP stream key to use to stream into this live video. Included in the response if an appropriate token is provided
        saveReplay:
          type: boolean
        replaySettings:
          $ref: '#/components/schemas/LiveVideoReplaySettings'
        permanentLive:
          description: User can stream multiple times in a permanent live
          type: boolean
        latencyMode:
          description: User can select live latency mode if enabled by the instance
          allOf:
            - $ref: '#/components/schemas/LiveVideoLatencyMode'
        schedules:
          type: array
          items:
            $ref: '#/components/schemas/LiveSchedule'

    LiveSchedule:
      properties:
        startAt:
          type: string
          format: date-time
          description: Date when the stream is scheduled to air at

    TokenSession:
      properties:
        id:
          type: integer
        currentSession:
          type: boolean
          description: Is this session the current one?
        loginDevice:
          type: string
          description: Device used to login
        loginIP:
          type: string
          format: ipv4
          description: IP address used to login
        loginDate:
          type: string
          format: date-time
          description: Date of the login
        lastActivityDevice:
          type: string
        lastActivityIP:
          type: string
          format: ipv4
        lastActivityDate:
          type: string
          format: date-time
        createdAt:
          type: string
          format: date-time

    RequestTwoFactorResponse:
      properties:
        otpRequest:
          type: object
          properties:
            requestToken:
              type: string
              description: The token to send to confirm this request
            secret:
              type: string
              description: The OTP secret
            uri:
              type: string
              description: The OTP URI

    VideoStudioCreateTask:
      type: array
      items:
        anyOf:
          -
            title: cut
            type: object
            properties:
              name:
                type: string
                enum:
                  - 'cut'
              options:
                type: object
                properties:
                  start:
                    type: integer
                  end:
                    type: integer
          -
            title: add-intro
            type: object
            properties:
              name:
                type: string
                enum:
                  - 'add-intro'
              options:
                type: object
                properties:
                  file:
                    type: string
                    format: binary
          -
            title: add-outro
            type: object
            properties:
              name:
                type: string
                enum:
                  - 'add-outro'
              options:
                type: object
                properties:
                  file:
                    type: string
                    format: binary
          -
            title: add-watermark
            type: object
            properties:
              name:
                type: string
                enum:
                  - 'add-watermark'
              options:
                type: object
                properties:
                  file:
                    type: string
                    format: binary
          -
            title: remove-segments
            type: object
            properties:
              name:
                type: string
                enum:
                  - 'remove-segments'
              options:
                type: object
                required:
                  - segments
                properties:
                  segments:
                    type: array
                    minItems: 1
                    items:
                      type: object
                      required:
                        - start
                        - end
                      properties:
                        start:
                          type: integer
                          minimum: 0
                        end:
                          type: integer
                          minimum: 1

    LiveVideoSessionResponse:
      properties:
        id:
          type: integer
        startDate:
          type: string
          format: date-time
          description: Start date of the live session
        endDate:
          type: string
          format: date-time
          nullable: true
          description: End date of the live session
        error:
          type: integer
          enum:
            - 1
            - 2
            - 3
            - 4
            - 5
          nullable: true
          description: >
            Error type if an error occurred during the live session:
              - `1`: Bad socket health (transcoding is too slow)
              - `2`: Max duration exceeded
              - `3`: Quota exceeded
              - `4`: Quota FFmpeg error
              - `5`: Video has been blacklisted during the live
        replayVideo:
          type: object
          description: Video replay information
          properties:
            id:
              type: number
            uuid:
              $ref: '#/components/schemas/UUIDv4'
            shortUUID:
              $ref: '#/components/schemas/shortUUID'

    PlaybackMetricCreate:
      properties:
        playerMode:
          type: string
          enum:
            - 'p2p-media-loader'
            - 'web-video'
        resolution:
          type: number
          description: Current player video resolution
        fps:
          type: number
          description: Current player video fps
        p2pEnabled:
          type: boolean
        p2pPeers:
          type: number
          description: P2P peers connected (doesn't include WebSeed peers)
        resolutionChanges:
          type: number
          description: How many resolution changes occurred since the last metric creation
        bufferStalled:
          type: number
          description: How many times buffer has been stalled since the last metric creation
        errors:
          type: number
          description: How many errors occurred since the last metric creation
        downloadedBytesP2P:
          type: number
          description: How many bytes were downloaded with P2P since the last metric creation
        downloadedBytesHTTP:
          type: number
          description: How many bytes were downloaded with HTTP since the last metric creation
        uploadedBytesP2P:
          type: number
          description: How many bytes were uploaded with P2P since the last metric creation
        videoId:
          oneOf:
            - $ref: '#/components/schemas/id'
            - $ref: '#/components/schemas/UUIDv4'
            - $ref: '#/components/schemas/shortUUID'
      required:
        - playerMode
        - resolutionChanges
        - errors
        - downloadedBytesP2P
        - downloadedBytesHTTP
        - uploadedBytesP2P
        - p2pEnabled
        - videoId

    RunnerRegistrationToken:
      properties:
        id:
          type: integer
        registrationToken:
          type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        registeredRunnersCount:
          type: integer

    Runner:
      properties:
        id:
          type: integer
        name:
          type: string
        description:
          type: string
        ip:
          type: string
        updatedAt:
          type: string
          format: date-time
        createdAt:
          type: string
          format: date-time
        lastContact:
          type: string
          format: date-time

    RunnerJobType:
      type: string
      enum:
        - vod-web-video-transcoding
        - vod-hls-transcoding
        - vod-audio-merge-transcoding
        - live-rtmp-hls-transcoding

    RunnerJobState:
      type: integer
      enum:
        - 1
        - 2
        - 3
        - 4
        - 5
        - 6
        - 7
        - 8
      description: >
        The runner job state:
          - `1` Pending
          - `2` Processing
          - `3` Completed
          - `4` Errored
          - `5` Waiting for a parent job
          - `6` Cancelled
          - `7` Parent had an error
          - `8` Parent has been cancelled

    RunnerJobStateConstant:
      type: object
      properties:
        id:
          $ref: '#/components/schemas/RunnerJobState'
        label:
          type: string
          example: 'Processing'

    RunnerJobPayload:
      anyOf:
        - type: object
          title: VOD web video transcoding
          properties:
            input:
              type: object
              properties:
                videoFileUrl:
                  type: string
            output:
              type: object
              properties:
                resolution:
                  type: number
                fps:
                  type: number
        - type: object
          title: VOD HLS transcoding
          properties:
            input:
              type: object
              properties:
                videoFileUrl:
                  type: string
            output:
              type: object
              properties:
                resolution:
                  type: number
                fps:
                  type: number
        - type: object
          title: VOD audio merge transcoding
          properties:
            input:
              type: object
              properties:
                audioFileUrl:
                  type: string
                previewFileUrl:
                  type: string
            output:
              type: object
              properties:
                resolution:
                  type: number
                fps:
                  type: number

    RunnerJob:
      properties:
        uuid:
          $ref: '#/components/schemas/UUIDv4'
        type:
          $ref: '#/components/schemas/RunnerJobType'
        state:
          $ref: '#/components/schemas/RunnerJobStateConstant'
        payload:
          $ref: '#/components/schemas/RunnerJobPayload'
        failures:
          type: integer
          description: Number of times a remote runner failed to process this job. After too many failures, the job in "error" state
        error:
          nullable: true
          type: string
          description: Error message if the job is errored
        progress:
          type: integer
          description: Percentage progress
        priority:
          type: integer
          description: Job priority (less has more priority)
        updatedAt:
          type: string
          format: date-time
        createdAt:
          type: string
          format: date-time
        startedAt:
          type: string
          format: date-time
        finishedAt:
          type: string
          format: date-time
        parent:
          nullable: true
          description: If job has a parent job
          type: object
          properties:
            type:
              $ref: '#/components/schemas/RunnerJobType'
            state:
              $ref: '#/components/schemas/RunnerJobStateConstant'
            uuid:
              $ref: '#/components/schemas/UUIDv4'
        runner:
          nullable: true
          description: If job is associated to a runner
          properties:
            id:
              type: number
            name:
              type: string
            description:
              type: string

    RunnerJobAdmin:
      allOf:
        - $ref: '#/components/schemas/RunnerJob'
        - type: object
          properties:
            privatePayload:
              type: object

    WatchedWordsLists:
      properties:
        id:
          $ref: '#/components/schemas/id'
        listName:
          type: string
        words:
          type: array
          items:
            type: string
        subscriptionUrl:
          type: string
          format: url
          nullable: true
        updatedAt:
          type: string
          format: date-time
          example: 2021-05-04T08:01:01.502Z
        createdAt:
          type: string
          format: date-time
          example: 2021-05-04T08:01:01.502Z

    WatchedWordsSubscription:
      properties:
        id:
          $ref: '#/components/schemas/id'
        name:
          type: string
        url:
          type: string
          format: url
        importedWordsCount:
          type: integer
          minimum: 0
        lastSyncAt:
          type: string
          format: date-time
          nullable: true
          example: 2021-05-04T08:01:01.502Z
        state:
          type: object
          properties:
            id:
              type: integer
              enum:
                - 1
                - 2
                - 3
                - 4
            label:
              type: string
        updatedAt:
          type: string
          format: date-time
          example: 2021-05-04T08:01:01.502Z
        createdAt:
          type: string
          format: date-time
          example: 2021-05-04T08:01:01.502Z

    VideoPassword:
      properties:
        id:
          $ref: '#/components/schemas/id'
        password:
          type: string
          minLength: 2
        videoId:
          $ref: '#/components/schemas/id'
    VideoPasswordList:
      properties:
        total:
          type: integer
          example: 1
        data:
          type: array
          items:
              $ref: '#/components/schemas/VideoPassword'
    AddVideoPasswords:
      type: array
      items:
        $ref: "#/components/schemas/VideoPassword/properties/password"
      uniqueItems: true

    VideoEmbedPrivacy:
      type: integer
      enum:
        - 1
        - 2
        - 3
        - 4
      description: >
        The video embed privacy level:
          - `1` All allowed: anyone can embed the video
          - `2` Allowlist: only the domains in the allowlist can embed the video
          - `3` Remote restrictions: the remote instance has restrictions on where the video can be embedded
          - `4` Nobody can embed this video

    PlayerTheme:
      type: string
      enum:
        - galaxy
        - lucide
      description: The player theme to use

    PlayerThemeChannelSetting:
      type: string
      enum:
        - instance-default
        - galaxy
        - lucide
      description: >
        Player theme setting for a channel:
          - `instance-default` Use the instance default theme
          - `galaxy` Use the galaxy theme
          - `lucide` Use the lucide theme

    PlayerThemeVideoSetting:
      type: string
      enum:
        - channel-default
        - instance-default
        - galaxy
        - lucide
      description: >
        Player theme setting for a video:
          - `channel-default` Use the channel default theme
          - `instance-default` Use the instance default theme
          - `galaxy` Use the galaxy theme
          - `lucide` Use the lucide theme

    PlayerVideoSettings:
      type: object
      properties:
        theme:
          $ref: '#/components/schemas/PlayerThemeVideoSetting'
      description: Player settings for a video

    PlayerChannelSettings:
      type: object
      properties:
        theme:
          $ref: '#/components/schemas/PlayerThemeChannelSetting'
      description: Player settings for a channel

    PlayerVideoSettingsUpdate:
      type: object
      properties:
        theme:
          $ref: '#/components/schemas/PlayerThemeVideoSetting'
      required:
        - theme
      description: Player settings update for a video

    PlayerChannelSettingsUpdate:
      type: object
      properties:
        theme:
          $ref: '#/components/schemas/PlayerThemeChannelSetting'
      required:
        - theme
      description: Player settings update for a channel

    FileStorage:
      type: integer
      enum:
        - 0
        - 1
      description: >
        The file storage type:
          - `0` File system
          - `1` Object storage

    VideoChannelCollaborator:
      type: object
      description: Representation of a channel collaboration
      properties:
        id:
          $ref: '#/components/schemas/id'
        account:
          $ref: '#/components/schemas/AccountSummary'
        state:
          type: object
          properties:
            id:
              $ref: '#/components/schemas/VideoChannelCollaboratorState'
            label:
              type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time

    VideoChannelCollaboratorState:
      type: integer
      enum:
        - 1
        - 2
      description: |
        The user import state:
          - `1`: Pending
          - `2`: Accepted

---

--- METRICS ---
- Files Extracted: 15
- Estimated Token Budget: ~140319 tokens
- Canonical Reference: https://codewiki.google/github.com/Chocobozzz/PeerTube
