Files
meta-fuse/docs/api-reference.md
T
2026-05-25 23:47:48 +02:00

14 KiB

API Reference

Overview

meta-fuse exposes a REST API for FUSE operations, VFS management, and service discovery. The API server is built with Fastify and listens on port 3000 by default.

Base URL: http://localhost:3000


Health & Status

GET /health

Health check endpoint.

Response:

{
    "status": "ok",
    "timestamp": "2024-01-15T10:30:00.000Z",
    "service": "meta-fuse"
}

GET /api/health

Alias for /health.

GET /api/fuse/health

Alias for /health.

GET /api/fuse/stats

Get VFS statistics and state information.

Response:

{
    "fileCount": 5123,
    "directoryCount": 847,
    "totalSize": 15847392847362,
    "lastRefresh": "2024-01-15T10:30:00.000Z",
    "categories": {
        "Movies": 1523,
        "TV": 2847,
        "Anime": 753
    },
    "kvConnection": "connected",
    "fuseMount": "mounted"
}

FUSE Operations

POST /api/fuse/readdir

List contents of a virtual directory.

Request Body:

{
    "path": "/Movies/Action"
}

Response (200 OK):

{
    "entries": [
        "Die Hard (1988)",
        "Mad Max Fury Road (2015)",
        "The Dark Knight (2008)"
    ]
}

Response (404 Not Found):

{
    "error": "Directory not found"
}

POST /api/fuse/getattr

Get file or directory attributes.

Request Body:

{
    "path": "/Movies/Action/Die Hard (1988)/Die Hard.mkv"
}

Response (200 OK) - File:

{
    "size": 4831838208,
    "mode": "file",
    "permissions": 644,
    "uid": 1000,
    "gid": 1000,
    "atime": "2024-01-15T10:30:00Z",
    "mtime": "2024-01-15T10:30:00Z",
    "ctime": "2024-01-15T10:30:00Z",
    "sourcePath": "/files/watch/downloads/Die.Hard.1988.1080p.mkv"
}

Response (200 OK) - Directory:

{
    "mode": "directory",
    "permissions": 755,
    "uid": 1000,
    "gid": 1000
}

Response (404 Not Found):

{
    "error": "Path not found"
}

POST /api/fuse/exists

Check if a path exists in the VFS.

Request Body:

{
    "path": "/Movies/Action/Die Hard (1988)"
}

Response:

{
    "exists": true
}

POST /api/fuse/read

Get information for reading a file. Returns source path and optionally WebDAV URL.

Request Body:

{
    "path": "/Movies/Action/Die Hard (1988)/Die Hard.mkv"
}

Response (200 OK) - Regular file:

{
    "sourcePath": "/files/watch/downloads/Die.Hard.1988.1080p.mkv",
    "size": 4831838208
}

Response (200 OK) - File with WebDAV access:

{
    "sourcePath": "/files/watch/downloads/Die.Hard.1988.1080p.mkv",
    "size": 4831838208,
    "webdavUrl": "http://meta-core/webdav/watch/downloads/Die.Hard.1988.1080p.mkv"
}

Response (200 OK) - Virtual file with content:

{
    "sourcePath": null,
    "size": 256,
    "content": "VGhpcyBpcyBhIHZpcnR1YWwgZmlsZQ==",
    "contentEncoding": "base64"
}

Response (404 Not Found):

{
    "error": "File not found"
}

POST /api/fuse/metadata

Get full metadata for a virtual path.

Request Body:

{
    "path": "/Movies/Action/Die Hard (1988)/Die Hard.mkv"
}

Response (200 OK):

{
    "hashId": "bafkreiabc123...",
    "filePath": "watch/downloads/Die.Hard.1988.1080p.mkv",
    "title": "Die Hard",
    "year": "1988",
    "fileType": "video",
    "size": "4831838208",
    "extension": "mkv",
    "video/codec": "h265",
    "video/resolution": "1920x1080",
    "audio/codec": "aac",
    "audio/channels": "6"
}

Response (404 Not Found):

{
    "error": "Metadata not found"
}

GET /api/fuse/files

List all virtual files in the VFS.

Response:

{
    "files": [
        "/Movies/Action/Die Hard (1988)/Die Hard.mkv",
        "/Movies/Action/Mad Max Fury Road (2015)/Mad Max Fury Road.mkv",
        "/TV/Breaking Bad/Season 01/S01E01 - Pilot.mkv"
    ]
}

GET /api/fuse/directories

List all virtual directories in the VFS.

Response:

{
    "directories": [
        "/Movies",
        "/Movies/Action",
        "/Movies/Action/Die Hard (1988)",
        "/TV",
        "/TV/Breaking Bad",
        "/TV/Breaking Bad/Season 01"
    ]
}

POST /api/fuse/refresh

Trigger a VFS refresh. Re-reads metadata and rebuilds virtual paths.

Response:

{
    "status": "ok"
}

Renaming Rules

GET /api/fuse/rules

Get the current renaming rules configuration.

Response:

{
    "config": {
        "rules": [
            {
                "name": "Movies",
                "enabled": true,
                "priority": 100,
                "template": "/Movies/{genre}/{title} ({year})/{fileName}",
                "conditions": {
                    "operator": "and",
                    "conditions": [
                        { "field": "fileType", "operator": "equals", "value": "video" },
                        { "field": "mediaType", "operator": "equals", "value": "movie" }
                    ]
                }
            },
            {
                "name": "TV Shows",
                "enabled": true,
                "priority": 90,
                "template": "/TV/{title}/Season {season:pad2}/{title} - S{season:pad2}E{episode:pad2}.{extension}",
                "conditions": {
                    "operator": "and",
                    "conditions": [
                        { "field": "fileType", "operator": "equals", "value": "video" },
                        { "field": "mediaType", "operator": "equals", "value": "tv" }
                    ]
                }
            }
        ],
        "defaultRule": {
            "name": "Default",
            "template": "/Other/{fileName}",
            "conditions": { "operator": "and", "conditions": [] }
        },
        "lastModified": "2024-01-15T10:30:00Z"
    },
    "lastModified": "2024-01-15T10:30:00Z"
}

PUT /api/fuse/rules

Update the renaming rules configuration. Automatically triggers VFS refresh.

Request Body:

{
    "config": {
        "rules": [
            {
                "name": "Movies",
                "enabled": true,
                "priority": 100,
                "template": "/Movies/{title} ({year})/{fileName}",
                "conditions": {
                    "operator": "and",
                    "conditions": [
                        { "field": "fileType", "operator": "equals", "value": "video" }
                    ]
                }
            }
        ]
    }
}

Response (200 OK):

{
    "success": true,
    "refreshed": true
}

Response (400 Bad Request) - Validation errors:

{
    "success": false,
    "errors": [
        "Rule \"Movies\": Unknown variable 'unknownVar' in template",
        "Rule \"TV Shows\": Invalid condition operator 'matches'"
    ]
}

POST /api/fuse/rules/preview

Preview how files would be renamed with the given rules.

Request Body:

{
    "rules": [
        {
            "name": "Movies",
            "template": "/New Movies/{title} ({year})/{fileName}",
            "conditions": {
                "operator": "and",
                "conditions": [
                    { "field": "fileType", "operator": "equals", "value": "video" }
                ]
            }
        }
    ],
    "limit": 10
}

Response:

{
    "previews": [
        {
            "hashId": "bafkreiabc123...",
            "currentPath": "/Movies/Action/Die Hard (1988)/Die Hard.mkv",
            "newPath": "/New Movies/Die Hard (1988)/Die Hard.mkv",
            "ruleName": "Movies"
        },
        {
            "hashId": "bafkreixyz789...",
            "currentPath": "/TV/Breaking Bad/Season 01/S01E01.mkv",
            "newPath": null,
            "ruleName": null,
            "reason": "No matching rule"
        }
    ],
    "total": 5123,
    "sampled": 10
}

POST /api/fuse/rules/validate

Validate a single renaming rule.

Request Body:

{
    "rule": {
        "name": "Test Rule",
        "template": "/Test/{title|originalTitle} ({year})/{fileName}",
        "conditions": {
            "operator": "and",
            "conditions": [
                { "field": "fileType", "operator": "equals", "value": "video" }
            ]
        }
    },
    "sampleMetadata": {
        "title": "Inception",
        "originalTitle": "Inception",
        "year": "2010",
        "fileName": "Inception.mkv"
    }
}

Response (valid rule):

{
    "valid": true,
    "errors": [],
    "warnings": [],
    "sampleOutput": "/Test/Inception (2010)/Inception.mkv"
}

Response (invalid rule):

{
    "valid": false,
    "errors": [
        "Unknown variable 'unknownField' in template"
    ],
    "warnings": [
        "Variable 'director' is rarely available in metadata"
    ],
    "sampleOutput": null
}

GET /api/fuse/rules/variables

Get list of available template variables.

Response:

{
    "variables": [
        {
            "name": "title",
            "description": "Media title",
            "example": "Inception"
        },
        {
            "name": "originalTitle",
            "description": "Original language title",
            "example": "Inception"
        },
        {
            "name": "year",
            "description": "Release year",
            "example": "2010"
        },
        {
            "name": "season",
            "description": "Season number (TV shows)",
            "example": "1",
            "modifiers": ["pad2", "pad3"]
        },
        {
            "name": "episode",
            "description": "Episode number (TV shows)",
            "example": "5",
            "modifiers": ["pad2", "pad3"]
        },
        {
            "name": "fileName",
            "description": "Original filename",
            "example": "Movie.2024.1080p.mkv"
        },
        {
            "name": "extension",
            "description": "File extension",
            "example": "mkv"
        },
        {
            "name": "fileType",
            "description": "Type of file",
            "example": "video"
        },
        {
            "name": "genre",
            "description": "Primary genre",
            "example": "Action"
        }
    ]
}

Service Discovery

GET /api/services

List all discovered MetaMesh services.

Response:

{
    "services": [
        {
            "name": "meta-sort",
            "url": "http://metasort-app",
            "api": "http://metasort-app/api",
            "status": "healthy",
            "role": "writer"
        },
        {
            "name": "meta-fuse",
            "url": "http://metafuse-app",
            "api": "http://metafuse-app/api",
            "status": "healthy",
            "role": "reader"
        },
        {
            "name": "meta-stremio",
            "url": "http://metastremio-app",
            "api": "http://metastremio-app/api",
            "status": "healthy",
            "role": "reader"
        }
    ],
    "current": "meta-fuse",
    "leader": {
        "hostname": "metacore-app",
        "baseUrl": "http://localhost:8083",
        "apiUrl": "http://meta-core:9000",
        "redisUrl": "redis://meta-core:6379",
        "webdavUrl": "http://localhost:8083/webdav"
    }
}

Error Responses

All endpoints may return these error responses:

400 Bad Request

Missing or invalid parameters.

{
    "error": "Missing or invalid \"path\" parameter"
}

404 Not Found

Resource not found.

{
    "error": "File not found"
}

500 Internal Server Error

Server-side error.

{
    "error": "Failed to process request"
}

Template Syntax

Basic Variables

{variableName}        → Replaced with metadata value
{title}               → "Inception"
{year}                → "2010"

Variable with Fallback

{title|originalTitle} → Uses title, falls back to originalTitle
{genre|"Unknown"}     → Uses genre, falls back to literal "Unknown"

Variable Modifiers

{season:pad2}         → "01" (zero-padded to 2 digits)
{episode:pad3}        → "001" (zero-padded to 3 digits)
{title:lower}         → "inception" (lowercase)
{title:upper}         → "INCEPTION" (uppercase)

Condition Operators

Operator Description Example
equals Exact match { "field": "fileType", "operator": "equals", "value": "video" }
notEquals Not equal { "field": "fileType", "operator": "notEquals", "value": "subtitle" }
contains Contains substring { "field": "title", "operator": "contains", "value": "Star" }
startsWith Starts with { "field": "fileName", "operator": "startsWith", "value": "[" }
endsWith Ends with { "field": "extension", "operator": "endsWith", "value": "mkv" }
exists Field exists { "field": "season", "operator": "exists" }
notExists Field missing { "field": "season", "operator": "notExists" }
greaterThan Numeric > { "field": "year", "operator": "greaterThan", "value": "2000" }
lessThan Numeric < { "field": "season", "operator": "lessThan", "value": "10" }

Condition Groups

{
    "operator": "and",
    "conditions": [
        { "field": "fileType", "operator": "equals", "value": "video" },
        {
            "operator": "or",
            "conditions": [
                { "field": "mediaType", "operator": "equals", "value": "movie" },
                { "field": "mediaType", "operator": "equals", "value": "tv" }
            ]
        }
    ]
}