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

672 lines
14 KiB
Markdown

# 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**:
```json
{
"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**:
```json
{
"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**:
```json
{
"path": "/Movies/Action"
}
```
**Response** (200 OK):
```json
{
"entries": [
"Die Hard (1988)",
"Mad Max Fury Road (2015)",
"The Dark Knight (2008)"
]
}
```
**Response** (404 Not Found):
```json
{
"error": "Directory not found"
}
```
### POST /api/fuse/getattr
Get file or directory attributes.
**Request Body**:
```json
{
"path": "/Movies/Action/Die Hard (1988)/Die Hard.mkv"
}
```
**Response** (200 OK) - File:
```json
{
"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:
```json
{
"mode": "directory",
"permissions": 755,
"uid": 1000,
"gid": 1000
}
```
**Response** (404 Not Found):
```json
{
"error": "Path not found"
}
```
### POST /api/fuse/exists
Check if a path exists in the VFS.
**Request Body**:
```json
{
"path": "/Movies/Action/Die Hard (1988)"
}
```
**Response**:
```json
{
"exists": true
}
```
### POST /api/fuse/read
Get information for reading a file. Returns source path and optionally WebDAV URL.
**Request Body**:
```json
{
"path": "/Movies/Action/Die Hard (1988)/Die Hard.mkv"
}
```
**Response** (200 OK) - Regular file:
```json
{
"sourcePath": "/files/watch/downloads/Die.Hard.1988.1080p.mkv",
"size": 4831838208
}
```
**Response** (200 OK) - File with WebDAV access:
```json
{
"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:
```json
{
"sourcePath": null,
"size": 256,
"content": "VGhpcyBpcyBhIHZpcnR1YWwgZmlsZQ==",
"contentEncoding": "base64"
}
```
**Response** (404 Not Found):
```json
{
"error": "File not found"
}
```
### POST /api/fuse/metadata
Get full metadata for a virtual path.
**Request Body**:
```json
{
"path": "/Movies/Action/Die Hard (1988)/Die Hard.mkv"
}
```
**Response** (200 OK):
```json
{
"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):
```json
{
"error": "Metadata not found"
}
```
### GET /api/fuse/files
List all virtual files in the VFS.
**Response**:
```json
{
"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**:
```json
{
"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**:
```json
{
"status": "ok"
}
```
---
## Renaming Rules
### GET /api/fuse/rules
Get the current renaming rules configuration.
**Response**:
```json
{
"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**:
```json
{
"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):
```json
{
"success": true,
"refreshed": true
}
```
**Response** (400 Bad Request) - Validation errors:
```json
{
"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**:
```json
{
"rules": [
{
"name": "Movies",
"template": "/New Movies/{title} ({year})/{fileName}",
"conditions": {
"operator": "and",
"conditions": [
{ "field": "fileType", "operator": "equals", "value": "video" }
]
}
}
],
"limit": 10
}
```
**Response**:
```json
{
"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**:
```json
{
"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):
```json
{
"valid": true,
"errors": [],
"warnings": [],
"sampleOutput": "/Test/Inception (2010)/Inception.mkv"
}
```
**Response** (invalid rule):
```json
{
"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**:
```json
{
"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**:
```json
{
"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.
```json
{
"error": "Missing or invalid \"path\" parameter"
}
```
### 404 Not Found
Resource not found.
```json
{
"error": "File not found"
}
```
### 500 Internal Server Error
Server-side error.
```json
{
"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
```json
{
"operator": "and",
"conditions": [
{ "field": "fileType", "operator": "equals", "value": "video" },
{
"operator": "or",
"conditions": [
{ "field": "mediaType", "operator": "equals", "value": "movie" },
{ "field": "mediaType", "operator": "equals", "value": "tv" }
]
}
]
}
```
---
## Related Documentation
- [README](../README.md) - Service overview
- [VFS Rebuild Architecture](vfs-rebuild-architecture.md) - State management
- [Streaming Architecture](streaming-architecture.md) - Event processing