{ "openapi": "3.0.3", "info": { "title": "CTH TK App APIs", "description": "Apifox import file for mini app drama and history APIs.", "version": "1.0.0" }, "servers": [ { "url": "http://localhost:3000", "description": "Local backend" } ], "tags": [ { "name": "App Dramas", "description": "Mini app drama APIs" }, { "name": "App History", "description": "Mini app playback history APIs" } ], "paths": { "/api/app/v1/dramas": { "get": { "tags": ["App Dramas"], "summary": "短剧列表", "operationId": "listAppDramas", "parameters": [ { "$ref": "#/components/parameters/Page" }, { "$ref": "#/components/parameters/PageSize10" } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [ { "$ref": "#/components/schemas/ApiResponseBase" }, { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/AppDramaPage" } } } ] } } } } } } }, "/api/app/v1/dramas/recommended": { "get": { "tags": ["App Dramas"], "summary": "推荐短剧列表", "operationId": "listRecommendedAppDramas", "parameters": [ { "$ref": "#/components/parameters/Page" }, { "$ref": "#/components/parameters/PageSize10" } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [ { "$ref": "#/components/schemas/ApiResponseBase" }, { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/AppDramaPage" } } } ] } } } } } } }, "/api/app/v1/dramas/presearch": { "get": { "tags": ["App Dramas"], "summary": "关键字预查询视频列表", "operationId": "presearchAppDramaVideos", "parameters": [ { "name": "keyword", "in": "query", "description": "用户输入关键字;空值返回空列表", "required": false, "schema": { "type": "string" }, "example": "skyline" }, { "$ref": "#/components/parameters/Page" }, { "$ref": "#/components/parameters/PageSize10" } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [ { "$ref": "#/components/schemas/ApiResponseBase" }, { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/VideoPresearchPage" } } } ] } } } } } } }, "/api/app/v1/dramas/{id}/episodes": { "get": { "tags": ["App Dramas"], "summary": "短剧剧集列表", "operationId": "listAppDramaEpisodes", "parameters": [ { "$ref": "#/components/parameters/DramaIdPath" }, { "$ref": "#/components/parameters/Page" }, { "$ref": "#/components/parameters/PageSize20" } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [ { "$ref": "#/components/schemas/ApiResponseBase" }, { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/AppEpisodePage" } } } ] } } } }, "404": { "$ref": "#/components/responses/ErrorResponse" } } } }, "/api/app/v1/dramas/{id}": { "get": { "tags": ["App Dramas"], "summary": "短剧详情", "operationId": "getAppDrama", "parameters": [ { "$ref": "#/components/parameters/DramaIdPath" } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [ { "$ref": "#/components/schemas/ApiResponseBase" }, { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/AppDramaDetail" } } } ] } } } }, "404": { "$ref": "#/components/responses/ErrorResponse" } } } }, "/api/app/v1/history": { "get": { "tags": ["App History"], "summary": "播放历史列表", "operationId": "listAppHistory", "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/Page" }, { "$ref": "#/components/parameters/PageSize20" } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [ { "$ref": "#/components/schemas/ApiResponseBase" }, { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/PlaybackHistoryPage" } } } ] } } } }, "401": { "$ref": "#/components/responses/ErrorResponse" } } }, "post": { "tags": ["App History"], "summary": "上报播放历史", "operationId": "upsertAppHistory", "security": [ { "bearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpsertPlaybackHistoryRequest" }, "example": { "episodeId": 123, "progressSeconds": 86, "completed": false, "occurredAt": "2026-07-02T10:00:00.000Z" } } } }, "responses": { "201": { "description": "Created", "content": { "application/json": { "schema": { "allOf": [ { "$ref": "#/components/schemas/ApiResponseBase" }, { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/PlaybackHistoryRecord" } } } ] } } } }, "400": { "$ref": "#/components/responses/ErrorResponse" }, "401": { "$ref": "#/components/responses/ErrorResponse" }, "404": { "$ref": "#/components/responses/ErrorResponse" } } } } }, "components": { "securitySchemes": { "bearerAuth": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } }, "parameters": { "DramaIdPath": { "name": "id", "in": "path", "required": true, "schema": { "type": "integer", "minimum": 1 }, "example": 1 }, "Page": { "name": "page", "in": "query", "required": false, "schema": { "type": "integer", "minimum": 1, "default": 1 } }, "PageSize10": { "name": "pageSize", "in": "query", "required": false, "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 10 } }, "PageSize20": { "name": "pageSize", "in": "query", "required": false, "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 20 } } }, "responses": { "ErrorResponse": { "description": "Error response", "content": { "application/json": { "schema": { "allOf": [ { "$ref": "#/components/schemas/ApiResponseBase" }, { "type": "object", "properties": { "code": { "type": "integer", "example": 404 }, "data": { "type": "object", "example": {} }, "message": { "type": "string", "example": "Not found" } } } ] } } } } }, "schemas": { "ApiResponseBase": { "type": "object", "required": ["code", "data", "message", "timestamp", "requestId", "cost"], "properties": { "code": { "type": "integer", "description": "业务响应码;成功为 0,错误为 HTTP 状态码", "example": 0 }, "data": { "type": "object" }, "message": { "type": "string", "example": "success" }, "timestamp": { "type": "integer", "format": "int64", "example": 1782986400000 }, "requestId": { "type": "string", "example": "550e8400-e29b-41d4-a716-446655440000" }, "cost": { "type": "string", "example": "12ms" } } }, "Pagination": { "type": "object", "required": ["page", "pageSize", "total"], "properties": { "page": { "type": "integer", "example": 1 }, "pageSize": { "type": "integer", "example": 10 }, "total": { "type": "integer", "example": 100 } } }, "AppDrama": { "type": "object", "required": ["id", "title", "coverUrl", "type", "tags", "status", "sortOrder", "isRecommended", "onlineVersion", "totalEpisodes", "publishedEpisodes", "createdAt", "updatedAt"], "properties": { "id": { "type": "integer", "example": 1 }, "tiktokAlbumId": { "type": "string", "nullable": true }, "title": { "type": "string", "example": "Published Drama" }, "description": { "type": "string", "nullable": true }, "coverId": { "type": "integer", "nullable": true }, "coverUrl": { "type": "string", "example": "https://cdn.example.com/cover.jpg" }, "type": { "type": "string", "example": "romance" }, "tags": { "type": "array", "items": { "type": "string" } }, "region": { "type": "string", "nullable": true }, "language": { "type": "string", "nullable": true }, "year": { "type": "integer", "nullable": true }, "status": { "type": "string", "enum": ["draft", "scheduled", "published", "offline"], "example": "published" }, "sortOrder": { "type": "integer", "example": 0 }, "isRecommended": { "type": "boolean", "example": true }, "onlineVersion": { "type": "integer", "example": 1 }, "totalEpisodes": { "type": "integer", "example": 20 }, "publishedEpisodes": { "type": "integer", "example": 10 }, "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" } } }, "AppDramaDetail": { "allOf": [ { "$ref": "#/components/schemas/AppDrama" }, { "type": "object", "properties": { "portraitCoverUrl": { "type": "string", "nullable": true }, "landscapeCoverUrl": { "type": "string", "nullable": true } } } ] }, "AppDramaPage": { "type": "object", "required": ["list", "pagination"], "properties": { "list": { "type": "array", "items": { "$ref": "#/components/schemas/AppDrama" } }, "pagination": { "$ref": "#/components/schemas/Pagination" } } }, "AppEpisode": { "type": "object", "required": ["id", "dramaId", "albumId", "episodeNo", "seq", "title", "coverUrl", "durationSeconds", "isPaid", "freeType", "price", "status", "reviewStatus", "publishStatus", "createdAt", "updatedAt"], "properties": { "id": { "type": "integer", "example": 1 }, "dramaId": { "type": "integer", "example": 1 }, "albumId": { "type": "integer", "example": 1 }, "tiktokEpisodeId": { "type": "string", "nullable": true }, "episodeNo": { "type": "integer", "example": 1 }, "seq": { "type": "integer", "example": 1 }, "title": { "type": "string", "example": "Episode 1" }, "description": { "type": "string", "nullable": true }, "byteplusVid": { "type": "string", "nullable": true }, "coverId": { "type": "integer", "nullable": true }, "coverUrl": { "type": "string", "example": "https://cdn.example.com/episode.jpg" }, "videoUrl": { "type": "string", "nullable": true }, "storageBucket": { "type": "string", "nullable": true }, "objectKey": { "type": "string", "nullable": true }, "trialDurationSeconds": { "type": "integer", "nullable": true }, "durationSeconds": { "type": "integer", "example": 300 }, "width": { "type": "integer", "nullable": true }, "height": { "type": "integer", "nullable": true }, "isPaid": { "type": "boolean", "example": false }, "freeType": { "type": "string", "enum": ["free", "paid"], "example": "free" }, "unlockPrice": { "type": "integer", "nullable": true }, "price": { "type": "integer", "example": 0 }, "publishAt": { "type": "string", "format": "date-time", "nullable": true }, "nextReleaseAt": { "type": "string", "format": "date-time", "nullable": true }, "status": { "type": "string", "enum": ["draft", "scheduled", "published", "offline"], "example": "published" }, "reviewStatus": { "type": "string", "enum": ["not_submitted", "pending", "reviewing", "approved", "rejected"], "example": "approved" }, "reviewMessage": { "type": "string", "nullable": true }, "publishStatus": { "type": "string", "enum": ["draft", "scheduled", "published", "offline"], "example": "published" }, "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" } } }, "AppEpisodePage": { "type": "object", "required": ["list", "pagination"], "properties": { "list": { "type": "array", "items": { "$ref": "#/components/schemas/AppEpisode" } }, "pagination": { "$ref": "#/components/schemas/Pagination" } } }, "VideoPresearchItem": { "type": "object", "required": ["id", "dramaId", "episodeNo", "title", "coverUrl", "durationSeconds", "freeType", "price", "dramaTitle", "dramaCoverUrl"], "properties": { "id": { "type": "integer", "example": 1 }, "dramaId": { "type": "integer", "example": 1 }, "episodeNo": { "type": "integer", "example": 1 }, "title": { "type": "string", "example": "Pilot Video Match" }, "description": { "type": "string", "nullable": true }, "coverUrl": { "type": "string", "example": "https://cdn.example.com/episode.jpg" }, "durationSeconds": { "type": "integer", "example": 180 }, "byteplusVid": { "type": "string", "nullable": true }, "videoUrl": { "type": "string", "nullable": true }, "freeType": { "type": "string", "enum": ["free", "paid"], "example": "free" }, "price": { "type": "integer", "example": 0 }, "dramaTitle": { "type": "string", "example": "Skyline Keyword Saga" }, "dramaCoverUrl": { "type": "string", "example": "https://cdn.example.com/drama.jpg" } } }, "VideoPresearchPage": { "type": "object", "required": ["list", "pagination"], "properties": { "list": { "type": "array", "items": { "$ref": "#/components/schemas/VideoPresearchItem" } }, "pagination": { "$ref": "#/components/schemas/Pagination" } } }, "UpsertPlaybackHistoryRequest": { "type": "object", "required": ["episodeId", "progressSeconds"], "properties": { "episodeId": { "type": "integer", "minimum": 1, "example": 123 }, "progressSeconds": { "type": "integer", "minimum": 0, "example": 86 }, "completed": { "type": "boolean", "example": false }, "occurredAt": { "type": "string", "format": "date-time", "example": "2026-07-02T10:00:00.000Z" } } }, "PlaybackHistoryRecord": { "type": "object", "required": ["id", "userId", "dramaId", "episodeId", "progressSeconds", "durationSeconds", "completed", "lastPlayedAt", "createdAt", "updatedAt"], "properties": { "id": { "type": "integer", "example": 1 }, "userId": { "type": "integer", "example": 1 }, "dramaId": { "type": "integer", "example": 1 }, "episodeId": { "type": "integer", "example": 123 }, "progressSeconds": { "type": "integer", "example": 86 }, "durationSeconds": { "type": "integer", "example": 300 }, "completed": { "type": "boolean", "example": false }, "lastPlayedAt": { "type": "string", "format": "date-time" }, "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" } } }, "PlaybackHistoryListItem": { "type": "object", "required": ["id", "dramaId", "episodeId", "episodeNo", "title", "coverUrl", "progressSeconds", "durationSeconds", "completed", "lastPlayedAt", "dramaTitle", "dramaCoverUrl"], "properties": { "id": { "type": "integer", "example": 1 }, "dramaId": { "type": "integer", "example": 1 }, "episodeId": { "type": "integer", "example": 123 }, "episodeNo": { "type": "integer", "example": 1 }, "title": { "type": "string", "example": "History Episode" }, "coverUrl": { "type": "string", "example": "https://cdn.example.com/history-episode.jpg" }, "progressSeconds": { "type": "integer", "example": 86 }, "durationSeconds": { "type": "integer", "example": 300 }, "completed": { "type": "boolean", "example": false }, "lastPlayedAt": { "type": "string", "format": "date-time" }, "dramaTitle": { "type": "string", "example": "History Drama" }, "dramaCoverUrl": { "type": "string", "example": "https://cdn.example.com/history-drama.jpg" } } }, "PlaybackHistoryPage": { "type": "object", "required": ["list", "pagination"], "properties": { "list": { "type": "array", "items": { "$ref": "#/components/schemas/PlaybackHistoryListItem" } }, "pagination": { "$ref": "#/components/schemas/Pagination" } } } } } }