đŦ Videos
+ +Overview
+The POST /api/videos endpoint is used to retrieve videos
+ from the given source. It contains information about the videos,
+channels, and other relevant information.
Request
+POST /api/videos
{
+ "query": "kittens",
+ "channel": "my-channel",
+ "channels": ["my-channel", "another-channel"], // Channels supporting multiple sites/channels
+ "sort": "new",
+ "page": 1,
+ "pageSize": 40,
+ "clientVersion": "2.2.7-38", // {version}â{build}, useful for feature availability
+ "blockedKeywords": ["example"],
+ "blockedUploaders": ["uploader-id-123"],
+ // Your server's custom parameters will be added here
+ "quality": "hd",
+ "duration": "short",
+ "flavor": "mint_chocolate_chip"
+}
+Request Parameters
+| Field | +Type | +Default | +Description | +
|---|---|---|---|
query |
+string |
+"" |
+Search query | +
channel |
+string |
+â | +Single channel identifier (as defined in your server's status response) | +
channels |
+string[] |
+â | +Multiple channel identifiers to search across (overrides channel) |
+
sort |
+string |
+"relevance" |
+Sort option ID (as defined in your server's status response options) | +
page |
+number |
+1 |
+Page number for pagination | +
pageSize |
+number |
+40 |
+Results per page | +
clientVersion |
+string |
+â | +App version string (e.g., "2.2.7-38") |
+
blockedKeywords |
+string[] |
+[] |
+Keywords to exclude from results | +
blockedUploaders |
+string[] |
+[] |
+Uploader IDs to exclude from results | +
| (server options) | +any |
+â | +Any option IDs defined in your server's status response are forwarded as-is | +
Server-Defined Filter Options
+Filter parameters beyond the core ones above (e.g., duration,
+quality, content type, sexuality) are entirely defined by your server
+via the options array in the Status endpoint response. Whatever id values you expose there will be sent back verbatim when the user selects them. Your /api/videos handler receives them as top-level keys in the request body.
+
Response
+{
+ "pageInfo": {
+ "hasNextPage": true,
+ "recommendations": ["cats", "pets", "animals"],
+ "error": null, // e.g. "No results were found"
+ "message": null, // e.g. "Showing cached results" or "Some content filtered based on preferences"
+ "parameters": {
+ "totalResults": 1000
+ }
+ },
+ "items": [
+ {
+ "id": "c85017ca87477168d648727753c4ded8a35f173e22ef93743e707b296becb299",
+ "title": "20 Minutes of Adorable Kittens BEST Compilation",
+ "url": "https://www.example.com/watch?v=y0sF5xhGreA",
+ "duration": 110,
+ "channel": "my-channel",
+ "thumb": "https://i.example.com/vi/y0sF5xhGreA/hqdefault.jpg",
+ "views": 14622653,
+ "rating": 95,
+ "uploader": "Awesome Vids",
+ "uploaderUrl": "https://www.example.com/@awesomeVids",
+ "uploaderId": "awesomeVids",
+ "verified": false,
+ "isVR": false,
+ "tags": ["cats", "kittens", "pets"],
+ "categories": ["Animals", "Entertainment"],
+ "uploadedAt": "2025-01-03T10:15:54.000Z",
+ "preview": "https://example.com/preview.mp4",
+ "uploaderId": "petcollective",
+ "aspectRatio": 1.78,
+ "uploaderProfile": {
+ "id": "abc123",
+ "name": "Awesome Vids",
+ "avatar": "https://example.com/avatar.jpg",
+ "videoCount": 342,
+ "totalViews": 14500000
+ },
+ "formats": [
+ {
+ "url": "https://www.example.com/watch?v=y0sF5xhGreA",
+ "quality": 1080,
+ "format": "mp4",
+ "formatId": "mp4-1080",
+ "protocol": "m3u8_native",
+ "ext": "mp4",
+ "httpHeaders": {
+ "Referer": "https://www.example.com"
+ }
+ }
+ ],
+ "embed": {
+ "source": "https://www.example.com/watch?v=y0sF5xhGreA",
+ "html": "<iframe src='...' width='560' height='315'></iframe>",
+ "width": 560,
+ "height": 315
+ }
+ }
+ ]
+}
+Field Reference
+Response Root Fields
+| Field | +Type | +Description | +
|---|---|---|
pageInfo |
+PageInfo |
+Pagination and status metadata | +
items |
+Video[] |
+Array of video objects | +
PageInfo Object Fields
+| Field | +Type | +Required | +Description | +
|---|---|---|---|
hasNextPage |
+boolean |
+â | +Whether more results are available | +
recommendations |
+string[] |
+âĒ | +Suggested search terms | +
error |
+string |
+âĒ | +Error message (e.g., "No results were found") | +
message |
+string |
+âĒ | +Informational message (e.g., "Showing cached results") | +
parameters |
+object |
+âĒ | +Additional metadata (e.g. "cursor": "abc123") |
+
Error vs Message
+-
+
error: Use for actual errors that prevent normal operation (no results, API failure, invalid query)
+message: Use for informational notices + that don't indicate failure (cached results, filtered content, rate +limiting info, feature announcements)
+
Video Object Fields
+| Field | +Type | +Required | +Description | +
|---|---|---|---|
title |
+string |
+â | +Video title | +
url |
+string |
+â | +Video source URL | +
duration |
+number |
+â | +Video length in seconds | +
channel |
+string |
+â | +Source channel/platform identifier | +
thumb |
+string |
+â | +Thumbnail image URL | +
id |
+string |
+âĒ | +Unique video identifier (auto-generated if not provided) | +
network |
+string |
+â | +Alias for channel â added by the server on every response item |
+
isVR |
+boolean |
+â | +true when VR content is detected from tags â added by the server |
+
uploaderProfile |
+UploaderProfile |
+â | +Partial uploader profile card â added by the server when a profile exists | +
views |
+number |
+âĒ | +View count | +
rating |
+number |
+âĒ | +Video percent rating score | +
uploader |
+string |
+âĒ | +Content creator name | +
uploaderUrl |
+string |
+âĒ | +Creator's profile URL | +
uploaderId |
+string |
+âĒ | +Unique uploader identifier | +
tags |
+string[] |
+âĒ | +Array of content tags (ordering is up to your server) | +
categories |
+string[] |
+âĒ | +Array of content categories | +
uploadedAt |
+Date|String |
+âĒ | +Upload date (flexible format) | +
preview |
+string |
+âĒ | +Preview GIF/video URL | +
formats |
+Format[] |
+âĒ | +Video format array | +
aspectRatio |
+number |
+âĒ | +Video aspect ratio (e.g., 1.78 for 16:9) | +
embed |
+EmbedData |
+âĒ | +Embed data for Reddit-style content | +
isLive |
+boolean |
+âĒ | +true when the video is a live stream â replaces duration with a "LIVE" badge |
+
liveStatus |
+string |
+âĒ | +yt-dlp live status: "live", "not_live", "was_live", "post_live" â used alongside isLive for badge and availability UI |
+
availability |
+string |
+âĒ | +Content availability hint â "offline" shows an unavailable badge instead of duration |
+
Live & Availability Display
+The app uses isLive and liveStatus together to determine how a video card renders:
-
+
- Live badge shown when
isLive == trueorliveStatus == "live"â the duration label is hidden and replaced with a "LIVE" indicator.
+ - Unavailable badge shown when
availability == "offline", orliveStatusis"not_live"or"was_live"â again replacing the duration.
+ - Normal duration shown otherwise. +
During playback, the player also detects live streams from the HLS
+stream itself (indefinite duration) and adjusts transport controls
+accordingly â so isLive is not required for playback to behave correctly, but it ensures the video card UI is accurate before the stream is loaded.
UploaderProfile Object
+Attached to each video item when a known uploader profile exists. +Used to render the uploader row on video cards without a separate API +call.
+| Field | +Type | +Description | +
|---|---|---|
id |
+string |
+Uploader identifier | +
name |
+string |
+Display name | +
avatar |
+string \| null |
+Avatar image URL (canonical) | +
videoCount |
+number |
+Total indexed videos | +
totalViews |
+number |
+Aggregated view count | +
See JSON key names for camelCase vs snake_case and the legacy profile_picture_url avatar key.
Format Object Fields
+| Field | +Type | +Required | +Description | +
|---|---|---|---|
url |
+string |
+â | +Direct video stream URL | +
formatId |
+string |
+Auto-generated | +Format identifier (provided or auto-generated) | +
ext |
+string |
+âĒ | +File extension ("mp4", "webm") | +
protocol |
+string |
+âĒ | +Stream protocol ("https", "m3u8_native") - important for playback | +
httpHeaders |
+object |
+âĒ (đ CDN) | +Required headers for CDN authentication | +
height |
+number |
+âĒ (đą UX) | +Video height in pixels (240, 480, 720, 1080) - recommended for better format IDs | +
width |
+number |
+âĒ | +Video width in pixels | +
resolution |
+string |
+âĒ | +Resolution string ("720p" or "1280x720") | +
format |
+string |
+âĒ | +Format description | +
fps |
+number |
+âĒ | +Frames per second | +
quality |
+number |
+âĒ | +yt-dlp quality score (fallback for formatId generation) |
+
vcodec |
+string |
+âĒ | +Video codec ("avc1.640020", "h264") | +
acodec |
+string |
+âĒ | +Audio codec ("mp4a.40.2", "aac") | +
tbr |
+number |
+âĒ | +Total bitrate | +
abr |
+number |
+âĒ | +Audio bitrate | +
vbr |
+number |
+âĒ | +Video bitrate | +
dynamicRange |
+string |
+âĒ | +Dynamic range ("SDR", "HDR") | +
aspectRatio |
+number |
+âĒ | +Video aspect ratio | +
filesize |
+number |
+âĒ | +File size in bytes | +
language |
+string |
+âĒ | +Audio language | +
container |
+string |
+âĒ | +Container format | +
downloaderOptions |
+object |
+âĒ | +Download configuration (defaults to 1MB chunks) | +
CDN Authentication
+Many premium/CDN streams require httpHeaders for authentication. Common headers include:
-
+
User-Agent- Required by most CDNs
+Referer- Required for hotlink protection
+Accept,Accept-Language- For content negotiation
+
Format ID Generation
+If formatId is not provided, it's auto-generated in this order:
-
+
{format}_{height}p(e.g., "mp4_720p")
+{format}_{resolution}(e.g., "mp4_1280x720")
+{format}_{quality}(e.g., "mp4_2.5")
+{format}only
+
Best Practices
+-
+
- Only
urlis truly required - everything else is optional
+ - Include
heightfor meaningful format IDs and better user experience
+ - Add
httpHeadersfor CDN streams that need authentication
+ - Providing
formatsbypasses yt-dlp extraction (faster response)
+ - Providing
previewavoids on-device preview generation
+