import { useState, useEffect, useCallback } from 'react'; import { RulesEditor } from './components/RulesEditor'; import ServiceNav from './components/ServiceNav'; import { WebdavTokens } from './components/WebdavTokens'; interface Stats { fileCount: number; directoryCount: number; totalSize: number; lastRefresh: string | null; redisConnected: boolean; } interface HealthStatus { status: string; timestamp: string; service: string; } function formatBytes(bytes: number): string { if (bytes === 0) return '0 B'; const k = 1024; const sizes = ['B', 'KB', 'MB', 'GB', 'TB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; } function formatTime(isoString: string | null): string { if (!isoString) return 'Never'; const date = new Date(isoString); return date.toLocaleTimeString(); } function App() { const [stats, setStats] = useState(null); const [health, setHealth] = useState(null); const [directories, setDirectories] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [refreshing, setRefreshing] = useState(false); const [showRules, setShowRules] = useState(false); const [showSetup, setShowSetup] = useState(false); const [showTokens, setShowTokens] = useState(false); const fetchData = useCallback(async () => { try { const [statsRes, healthRes, dirsRes] = await Promise.all([ fetch('/api/fuse/stats'), fetch('/api/fuse/health'), fetch('/api/fuse/directories'), ]); if (!statsRes.ok || !healthRes.ok) { throw new Error('Failed to fetch data'); } const statsData = await statsRes.json(); const healthData = await healthRes.json(); const dirsData = await dirsRes.json(); setStats(statsData); setHealth(healthData); setDirectories(dirsData.directories || []); setError(null); } catch (err) { setError(err instanceof Error ? err.message : 'Unknown error'); } finally { setLoading(false); } }, []); const handleRefresh = async () => { setRefreshing(true); try { await fetch('/api/fuse/refresh', { method: 'POST' }); await fetchData(); } catch (err) { setError(err instanceof Error ? err.message : 'Refresh failed'); } finally { setRefreshing(false); } }; useEffect(() => { fetchData(); const dataInterval = setInterval(fetchData, 5000); return () => { clearInterval(dataInterval); }; }, [fetchData]); if (loading) { return (
Loading...
); } const isConnected = health?.status === 'ok' && stats?.redisConnected; return (

meta-fuse

Virtual filesystem service

{isConnected ? 'Connected' : 'Disconnected'}
{error &&
{error}
}

What is meta-fuse?

meta-fuse is a virtual filesystem that presents your media files in an organized structure based on metadata. It reads file information from the KV leader (via Redis) and creates a virtual view of your library without duplicating any files.

  • Access files organized by title, year, series, etc.
  • Mount via FUSE (native) or WebDAV (network drive)
  • No file duplication - virtual paths point to real files
  • Automatically updates when new files are processed
📁

WebDAV Files

Browse and access your organized media library. Mount as a network drive on any device.

/webdav

VFS Control

Files
{stats?.fileCount ?? 0}
Total files in VFS
Directories
{stats?.directoryCount ?? 0}
Total directories
Total Size
{formatBytes(stats?.totalSize ?? 0)}
Combined file size
Last Refresh
{formatTime(stats?.lastRefresh ?? null)}
From Redis metadata
Connection Status
API Status
{health?.status ?? 'unknown'}
Redis
{stats?.redisConnected ? 'Connected' : 'Disconnected'}
Service
{health?.service ?? 'unknown'}
Timestamp
{formatTime(health?.timestamp ?? null)}
setShowRules(!showRules)} >

Renaming Rules

{showRules ? '-' : '+'}
{showRules && ( )}
setShowTokens(!showTokens)} >

WebDAV Access Tokens

{showTokens ? '-' : '+'}
{showTokens && }

Virtual Directories

{directories.length === 0 ? (
No directories found. Waiting for metadata from meta-sort...
) : ( directories.slice(0, 20).map((dir) => (
📁 {dir}
)) )} {directories.length > 20 && (
... and {directories.length - 20} more directories
)}
setShowSetup(!showSetup)} >

Setup & Configuration

▼
{showSetup && (

FUSE Mount (Docker)

Mount the virtual filesystem directly from the container. Add this volume to your docker-compose.yml to access the organized files on your host:

volumes:
  - /path/on/host:/mnt/virtual:rw,shared

The virtual filesystem is available inside the container at /mnt/virtual

WebDAV Network Drive

Mount the virtual filesystem as a network drive on any device:

Windows: net use Z: http://<host>/webdav
macOS: Finder → Go → Connect to Server → http://<host>/webdav
Linux: sudo mount -t davfs http://<host>/webdav /mnt/vfs
)}
); } export default App;