{"openapi": "3.0.3", "info": {"title": "EasyProxy API", "version": "2.9.58", "description": "Interactive documentation for EasyProxy. Includes HLS/MPD proxying, extractor endpoints, key and license helpers, playlist generation, admin API, DVR/recording management, and compatibility endpoints inspired by MediaFlow Proxy."}, "servers": [{"url": "http://easyproxy.juh.mywire.org"}], "components": {"securitySchemes": {"ApiPasswordQuery": {"type": "apiKey", "in": "query", "name": "api_password", "description": "Primary auth method shown in docs. Header x-api-password is still accepted by the server."}}}, "paths": {"/api/info": {"get": {"summary": "Server information", "description": "Returns server status, loaded extractors, modules, and example endpoints.", "responses": {"200": {"description": "Server information JSON"}}}}, "/health": {"get": {"summary": "Health check", "description": "Simple health check endpoint returning OK status and app version.", "responses": {"200": {"description": "JSON with status and version"}}}}, "/generate_urls": {"post": {"summary": "Generate proxy URLs", "description": "Generate one or multiple compatibility URLs for clients.", "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"mediaflow_proxy_url": {"type": "string"}, "api_password": {"type": "string"}, "urls": {"type": "array", "items": {"type": "object"}}}}}}}, "responses": {"200": {"description": "Generated URL list"}}, "security": [{"ApiPasswordQuery": []}]}}, "/proxy/ip": {"get": {"summary": "Resolve public IP", "description": "Returns the public IP as seen through the configured proxy route.", "responses": {"200": {"description": "Public IP response"}}}}, "/proxy/manifest.m3u8": {"get": {"summary": "Legacy proxy manifest", "description": "Proxy a manifest using the legacy url parameter.", "parameters": [{"name": "url", "in": "query", "schema": {"type": "string"}, "required": true}, {"name": "api_password", "in": "query", "schema": {"type": "string"}}], "responses": {"200": {"description": "Proxied manifest or media response"}}, "security": [{"ApiPasswordQuery": []}]}}, "/proxy/hls/manifest.m3u8": {"get": {"summary": "Proxy HLS manifest", "description": "MediaFlow-compatible HLS proxy endpoint.", "parameters": [{"name": "d", "in": "query", "schema": {"type": "string"}, "required": true, "description": "Destination manifest URL"}, {"name": "api_password", "in": "query", "schema": {"type": "string"}}], "responses": {"200": {"description": "Proxied HLS manifest"}}, "security": [{"ApiPasswordQuery": []}]}}, "/proxy/hls/segment.{format}": {"get": {"summary": "HLS segment compatibility", "description": "Serve HLS segments (ts, m4s, mp4, vtt) through the proxy with proper headers.", "parameters": [{"name": "format", "in": "path", "schema": {"type": "string", "enum": ["ts", "m4s", "mp4", "vtt"]}, "required": true}], "responses": {"200": {"description": "Segment data"}}}}, "/proxy/mpd/manifest.m3u8": {"get": {"summary": "Proxy MPD as HLS", "description": "Converts or relays MPEG-DASH/MPD streams through EasyProxy.", "parameters": [{"name": "d", "in": "query", "schema": {"type": "string"}, "required": true, "description": "Destination MPD URL"}, {"name": "key_id", "in": "query", "schema": {"type": "string"}}, {"name": "key", "in": "query", "schema": {"type": "string"}}, {"name": "api_password", "in": "query", "schema": {"type": "string"}}], "responses": {"200": {"description": "Generated HLS manifest"}}, "security": [{"ApiPasswordQuery": []}]}}, "/proxy/mpd/manifest.mpd": {"get": {"summary": "Proxy MPD native", "description": "Proxy the native MPD manifest for DASH streams.", "parameters": [{"name": "d", "in": "query", "schema": {"type": "string"}, "required": true, "description": "Destination MPD URL"}, {"name": "api_password", "in": "query", "schema": {"type": "string"}}], "responses": {"200": {"description": "Proxied MPD manifest"}}, "security": [{"ApiPasswordQuery": []}]}}, "/proxy/mpd/segment/{session_id}/{tail:.*}": {"get": {"summary": "DASH segment serving", "description": "Serve DASH segments for an active MPD-to-HLS conversion session.", "parameters": [{"name": "session_id", "in": "path", "schema": {"type": "string"}, "required": true}, {"name": "tail", "in": "path", "schema": {"type": "string"}, "required": true}], "responses": {"200": {"description": "Segment data"}}}}, "/proxy/stream": {"get": {"summary": "Generic stream proxy", "description": "Generic MediaFlow-style stream endpoint for direct proxying.", "parameters": [{"name": "d", "in": "query", "schema": {"type": "string"}, "required": true}, {"name": "api_password", "in": "query", "schema": {"type": "string"}}], "responses": {"200": {"description": "Streamed response"}}, "security": [{"ApiPasswordQuery": []}]}}, "/playlist": {"get": {"summary": "Build a playlist", "description": "Combine multiple source URLs into a generated playlist.", "parameters": [{"name": "url", "in": "query", "schema": {"type": "string"}, "required": true}, {"name": "api_password", "in": "query", "schema": {"type": "string"}}], "responses": {"200": {"description": "Generated playlist"}}, "security": [{"ApiPasswordQuery": []}]}}, "/segment/{segment}": {"get": {"summary": "Legacy TS segment serving", "description": "Serve TS segments by their segment identifier.", "parameters": [{"name": "segment", "in": "path", "schema": {"type": "string"}, "required": true}], "responses": {"200": {"description": "Segment data"}}}}, "/decrypt/segment.{format}": {"get": {"summary": "Legacy decrypt segment", "description": "Decrypt and serve segments using ClearKey (legacy mode).", "parameters": [{"name": "format", "in": "path", "schema": {"type": "string", "enum": ["mp4", "ts"]}, "required": true}], "responses": {"200": {"description": "Decrypted segment"}}}}, "/ffmpeg_stream/{stream_id}/{filename}": {"get": {"summary": "FFmpeg live stream", "description": "Serve segments generated by FFmpeg for live transcoding streams.", "parameters": [{"name": "stream_id", "in": "path", "schema": {"type": "string"}, "required": true}, {"name": "filename", "in": "path", "schema": {"type": "string"}, "required": true}], "responses": {"200": {"description": "Segment or playlist"}}}}, "/extractor": {"get": {"summary": "Generic extractor", "description": "Resolve supported hosters into playable URLs.", "parameters": [{"name": "host", "in": "query", "schema": {"type": "string"}}, {"name": "url", "in": "query", "schema": {"type": "string"}}, {"name": "api_password", "in": "query", "schema": {"type": "string"}}], "responses": {"200": {"description": "Extractor response"}}, "security": [{"ApiPasswordQuery": []}]}}, "/extractor/video": {"get": {"summary": "Extractor compatibility endpoint", "description": "MediaFlow-compatible alias for video extractor requests.", "parameters": [{"name": "host", "in": "query", "schema": {"type": "string"}}, {"name": "url", "in": "query", "schema": {"type": "string"}}, {"name": "api_password", "in": "query", "schema": {"type": "string"}}], "responses": {"200": {"description": "Extractor response"}}, "security": [{"ApiPasswordQuery": []}]}}, "/extractor/video.{format}": {"get": {"summary": "Extractor format-suffix variants", "description": "Format-forced extractor variants. Supported extensions: m3u8, mp4, mpd, ts, m4s, vtt, aac, m4a, webm, mkv, avi, mov. All share the same parameters and handler.", "parameters": [{"name": "format", "in": "path", "schema": {"type": "string"}, "required": true}, {"name": "host", "in": "query", "schema": {"type": "string"}}, {"name": "url", "in": "query", "schema": {"type": "string"}}, {"name": "d", "in": "query", "schema": {"type": "string"}}, {"name": "api_password", "in": "query", "schema": {"type": "string"}}], "responses": {"200": {"description": "Extractor response"}}, "security": [{"ApiPasswordQuery": []}]}}, "/key": {"get": {"summary": "Fetch or transform decryption keys", "description": "Proxy AES-128 keys or derive license-related key material.", "parameters": [{"name": "key_url", "in": "query", "schema": {"type": "string"}}, {"name": "key", "in": "query", "schema": {"type": "string"}}, {"name": "key_id", "in": "query", "schema": {"type": "string"}}, {"name": "api_password", "in": "query", "schema": {"type": "string"}}], "responses": {"200": {"description": "Key response"}}, "security": [{"ApiPasswordQuery": []}]}}, "/license": {"get": {"summary": "License proxy", "description": "Proxy DRM license requests or handle ClearKey shortcuts.", "parameters": [{"name": "url", "in": "query", "schema": {"type": "string"}}, {"name": "clearkey", "in": "query", "schema": {"type": "string"}}, {"name": "api_password", "in": "query", "schema": {"type": "string"}}], "responses": {"200": {"description": "License response"}}, "security": [{"ApiPasswordQuery": []}]}, "post": {"summary": "License proxy POST", "description": "POST DRM license payloads to the upstream license server.", "requestBody": {"required": false, "content": {"application/octet-stream": {"schema": {"type": "string", "format": "binary"}}}}, "responses": {"200": {"description": "License response"}}, "security": [{"ApiPasswordQuery": []}]}}, "/api/admin/login": {"post": {"summary": "Admin login", "description": "Authenticate as admin. Sets a session cookie on success.", "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"password": {"type": "string"}}}}}}, "responses": {"200": {"description": "Login success"}, "401": {"description": "Invalid password"}}}}, "/api/admin/config": {"get": {"summary": "Get admin config", "description": "Retrieve the full server configuration as JSON.", "responses": {"200": {"description": "Configuration JSON"}}, "security": [{"ApiPasswordQuery": []}]}, "post": {"summary": "Update admin config", "description": "Update server configuration with a JSON payload.", "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "description": "Partial or full config update"}}}}, "responses": {"200": {"description": "Config updated"}}, "security": [{"ApiPasswordQuery": []}]}}, "/api/admin/config/download": {"get": {"summary": "Download config as file", "description": "Download the current configuration as a downloadable file.", "responses": {"200": {"description": "Config file download"}}, "security": [{"ApiPasswordQuery": []}]}}, "/api/admin/config/upload": {"post": {"summary": "Upload config file", "description": "Upload a configuration file to replace the current server config.", "requestBody": {"required": true, "content": {"multipart/form-data": {"schema": {"type": "object", "properties": {"file": {"type": "string", "format": "binary"}}}}}}, "responses": {"200": {"description": "Config uploaded and reloaded"}}, "security": [{"ApiPasswordQuery": []}]}}, "/api/admin/warp/toggle": {"post": {"summary": "Toggle WARP", "description": "Enable or disable Cloudflare WARP proxy routing.", "responses": {"200": {"description": "WARP toggled"}}, "security": [{"ApiPasswordQuery": []}]}}, "/api/admin/warp/reconnect": {"post": {"summary": "Reconnect WARP", "description": "Force WARP to disconnect, re-register, and reconnect.", "responses": {"200": {"description": "WARP reconnected"}}, "security": [{"ApiPasswordQuery": []}]}}, "/api/admin/extractor/proxy": {"post": {"summary": "Set extractor proxy", "description": "Override the proxy used by a specific extractor for testing.", "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"extractor": {"type": "string"}, "proxy": {"type": "string"}}}}}}, "responses": {"200": {"description": "Extractor proxy updated"}}, "security": [{"ApiPasswordQuery": []}]}}, "/api/admin/speedtest": {"post": {"summary": "Run speed test", "description": "Test download speed through a specified proxy or direct connection.", "responses": {"200": {"description": "Speed test results"}}, "security": [{"ApiPasswordQuery": []}]}}, "/recordings": {"get": {"summary": "Recordings UI page", "description": "DVR/recording management web interface.", "responses": {"200": {"description": "HTML page"}}}}, "/record": {"get": {"summary": "Start recording via GET", "description": "Quick-start a recording from a URL query parameter.", "parameters": [{"name": "url", "in": "query", "schema": {"type": "string"}, "required": true}, {"name": "api_password", "in": "query", "schema": {"type": "string"}}], "responses": {"200": {"description": "Recording started"}}, "security": [{"ApiPasswordQuery": []}]}}, "/record/stop/{id}": {"get": {"summary": "Stop recording via GET", "description": "Stop a recording by ID via GET request.", "parameters": [{"name": "id", "in": "path", "schema": {"type": "string"}, "required": true}], "responses": {"200": {"description": "Recording stopped"}}}}, "/api/recordings": {"get": {"summary": "List recordings", "description": "Get a paginated list of all recordings, with optional status filter.", "parameters": [{"name": "status", "in": "query", "schema": {"type": "string", "enum": ["active", "completed", "failed"]}}], "responses": {"200": {"description": "Recordings list"}}}}, "/api/recordings/active": {"get": {"summary": "Active recordings", "description": "Get a list of currently active recordings.", "responses": {"200": {"description": "Active recordings list"}}}}, "/api/recordings/start": {"post": {"summary": "Start recording", "description": "Start a new DVR recording for a specified stream URL.", "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"url": {"type": "string"}, "stream_type": {"type": "string"}}}}}}, "responses": {"200": {"description": "Recording started"}, "400": {"description": "Invalid request"}}}}, "/api/recordings/{id}": {"get": {"summary": "Get recording details", "description": "Retrieve metadata for a specific recording.", "parameters": [{"name": "id", "in": "path", "schema": {"type": "string"}, "required": true}], "responses": {"200": {"description": "Recording metadata"}}}, "delete": {"summary": "Delete recording", "description": "Delete a recording by ID.", "parameters": [{"name": "id", "in": "path", "schema": {"type": "string"}, "required": true}], "responses": {"200": {"description": "Recording deleted"}}}}, "/api/recordings/{id}/delete": {"get": {"summary": "Delete recording via GET", "description": "Delete a recording by ID using a GET request (legacy compatibility).", "parameters": [{"name": "id", "in": "path", "schema": {"type": "string"}, "required": true}], "responses": {"200": {"description": "Recording deleted"}}}}, "/api/recordings/{id}/stop": {"post": {"summary": "Stop recording", "description": "Stop an active recording by ID.", "parameters": [{"name": "id", "in": "path", "schema": {"type": "string"}, "required": true}], "responses": {"200": {"description": "Recording stopped"}}}}, "/api/recordings/{id}/download": {"get": {"summary": "Download recording", "description": "Download a completed recording file.", "parameters": [{"name": "id", "in": "path", "schema": {"type": "string"}, "required": true}], "responses": {"200": {"description": "Recording file download"}}}}, "/api/recordings/{id}/stream": {"get": {"summary": "Stream recording", "description": "Stream a completed recording as HLS.", "parameters": [{"name": "id", "in": "path", "schema": {"type": "string"}, "required": true}], "responses": {"200": {"description": "HLS stream"}}}}, "/api/recordings/all": {"delete": {"summary": "Delete all recordings", "description": "Delete all recordings, optionally filtering by status.", "parameters": [{"name": "status", "in": "query", "schema": {"type": "string", "enum": ["active", "completed", "failed"]}}], "responses": {"200": {"description": "All matching recordings deleted"}}}}}}