# API Reference - SamCloud Music

**Version**: 2.0.0  
**Base URL**: `http://localhost:6544`  
**Last Updated**: July 1, 2025 - Current Session  
**Status**: 🔄 Active Development - Some endpoints in testing

---

## ⚠️ Current Endpoint Status

| Endpoint | Status | Notes |
|----------|--------|-------|
| `GET /` | ✅ Working | Main SPA interface |
| `POST /api/jellyfin/auth` | ✅ Working | Authentication tested |
| `GET /api/jellyfin/library` | ⚠️ Testing | 500 error being fixed |
| `POST /api/download` | ✅ Working | Download functionality |
| WebSocket events | ⚠️ Testing | Progress updates |

---

## 🌐 HTTP Endpoints

### **Core Application**

#### `GET /`
**Description**: Main application interface  
**Returns**: HTML single-page application  
**Content-Type**: `text/html`

**Response**: 
```html
<!DOCTYPE html>
<html>
<!-- 3898-line SPA with Apple Music-style interface -->
</html>
```

#### `GET /static/<path:filename>`
**Description**: Static assets (CSS, JS, images)  
**Parameters**:
- `filename` (path): Relative path to static file
**Returns**: Static file content  
**Examples**:
- `/static/socket.io.js` - Socket.IO client library
- `/static/manifest.json` - PWA manifest

---

### **Jellyfin Integration**

#### `POST /api/jellyfin/auth`
**Description**: Authenticate with Jellyfin server  
**Content-Type**: `application/json`

**Request Body**:
```json
{
  "server_url": "https://jellyfin.samcloud.ca",
  "username": "your_username", 
  "password": "your_password"
}
```

**Success Response** (200):
```json
{
  "success": true,
  "user_id": "abc123def456",
  "access_token": "jwt_token_here",
  "server_info": {
    "name": "My Jellyfin Server",
    "version": "10.8.0",
    "id": "server_uuid"
  }
}
```

**Error Response** (401):
```json
{
  "success": false,
  "error": "Authentication failed - Invalid username or password"
}
```

**Error Response** (500):
```json
{
  "success": false,
  "error": "Connection failed: [detailed error message]"
}
```

#### `GET /api/jellyfin/library`
**Description**: Get library items from Jellyfin server  
**Authentication**: Requires prior successful authentication  
**Query Parameters**:
- `type` (string, optional): Item type filter ("Audio", "Album", "Artist") - default: "Audio"
- `limit` (integer, optional): Maximum items to return - default: 100
- `start` (integer, optional): Pagination offset - default: 0

**Example Request**:
```
GET /api/jellyfin/library?type=Audio&limit=200&start=0
```

**Success Response** (200):
```json
{
  "success": true,
  "items": [
    {
      "id": "jellyfin_item_id",
      "name": "Song Title",
      "type": "Audio",
      "artist": "Artist Name",
      "album": "Album Name", 
      "duration": 240,
      "year": 2023,
      "image_url": "https://jellyfin.samcloud.ca/Items/abc123/Images/Primary",
      "stream_url": "https://jellyfin.samcloud.ca/Audio/abc123/stream"
    }
  ],
  "total": 1500
}
```

**Error Response** (401):
```json
{
  "success": false,
  "error": "Not authenticated with Jellyfin"
}
```

**Error Response** (500):
```json
{
  "success": false,
  "error": "Failed to fetch library"
}
```

---

### **Download System**

#### `GET /api/downloads/stats`
**Description**: Get download statistics and history  
**Authentication**: None required

**Success Response** (200):
```json
{
  "success": true,
  "stats": {
    "total_downloads": 45,
    "completed_downloads": 42,
    "failed_downloads": 2,
    "pending_downloads": 1,
    "success_rate": 93.3,
    "total_size_mb": 1250.5,
    "average_duration_seconds": 240
  }
}
```

**Error Response** (500):
```json
{
  "success": false,
  "error": "Failed to get download statistics"
}
```

---

## ⚡ WebSocket Events

**Connection**: `ws://localhost:6544/socket.io`  
**Transport**: WebSocket with polling fallback  
**Protocol**: Socket.IO v4+

### **Client → Server Events**

#### `search`
**Description**: Perform music search via Spotify API  
**Parameters**:
```javascript
{
  "query": "artist song album",     // Search query string
  "type": "all",                   // Filter: "all", "track", "album", "artist", "playlist"
  "limit": 20                      // Maximum results (optional, default: 20)
}
```

**Example**:
```javascript
socket.emit('search', {
  query: 'Billie Eilish bad guy',
  type: 'track',
  limit: 10
});
```

#### `download_item`
**Description**: Request download of a music item  
**Parameters**:
```javascript
{
  "url": "spotify:track:4uLU6hMCjMI75M1A2tKUQC",  // Spotify URL
  "type": "track",                                // Item type
  "name": "Song Title",                          // Display name
  "artist": "Artist Name",                       // Artist name
  "id": "dl_1672531200000",                     // Unique download ID
  "timestamp": "2023-01-01T00:00:00.000Z"       // Request timestamp
}
```

**Example**:
```javascript
socket.emit('download_item', {
  url: 'spotify:track:4uLU6hMCjMI75M1A2tKUQC',
  type: 'track',
  name: 'bad guy',
  artist: 'Billie Eilish',
  id: 'dl_' + Date.now(),
  timestamp: new Date().toISOString()
});
```

#### `get_status`
**Description**: Request current download status  
**Parameters**: None

**Example**:
```javascript
socket.emit('get_status');
```

#### `cancel_all`
**Description**: Cancel all pending downloads  
**Parameters**: None

**Example**:
```javascript
socket.emit('cancel_all');
```

### **Server → Client Events**

#### `search_results`
**Description**: Search results from Spotify API  
**Data Structure**:
```javascript
{
  "query": "billie eilish bad guy",
  "type": "track", 
  "results": [
    {
      "id": "4uLU6hMCjMI75M1A2tKUQC",
      "name": "bad guy",
      "artist": "Billie Eilish", 
      "image": "https://i.scdn.co/image/ab67616d0000b273a8248c9e0b6c9f...",
      "type": "track",
      "url": "spotify:track:4uLU6hMCjMI75M1A2tKUQC",
      "duration": 194840,
      "explicit": false
    }
  ]
}
```

#### `search_error`
**Description**: Search error occurred  
**Data Structure**:
```javascript
{
  "message": "Search failed: Rate limit exceeded",
  "code": "RATE_LIMIT",
  "query": "original search query"
}
```

#### `download_progress`
**Description**: Real-time download progress update  
**Data Structure**:
```javascript
{
  "id": "dl_1672531200000",
  "url": "spotify:track:4uLU6hMCjMI75M1A2tKUQC",
  "name": "bad guy",
  "artist": "Billie Eilish",
  "type": "track",
  "status": "downloading",           // Status: "queued", "searching", "downloading", "processing", "completed", "failed"
  "progress": 65,                    // Percentage (0-100)
  "message": "Downloading audio...", // Human-readable status
  "speed": 1.2,                     // Download speed in MB/s
  "downloaded": 3.1,                // Downloaded size in MB
  "total": 4.8,                     // Total file size in MB
  "time_remaining": 45,             // Estimated seconds remaining
  "stages": {
    "search": { "status": "completed", "progress": 100 },
    "download": { "status": "active", "progress": 65 },
    "convert": { "status": "pending", "progress": 0 },
    "finalize": { "status": "pending", "progress": 0 }
  }
}
```

#### `download_complete`
**Description**: Download finished successfully  
**Data Structure**:
```javascript
{
  "id": "dl_1672531200000",
  "url": "spotify:track:4uLU6hMCjMI75M1A2tKUQC",
  "name": "bad guy",
  "artist": "Billie Eilish",
  "type": "track",
  "status": "completed",
  "progress": 100,
  "message": "Download complete",
  "file_path": "/data/Billie Eilish/WHEN WE ALL FALL ASLEEP, WHERE DO WE GO? - (2019)/Billie Eilish - bad guy.mp3",
  "file_size": 4.8,
  "duration": 194.84,
  "quality": "320kbps"
}
```

#### `download_error`
**Description**: Download failed  
**Data Structure**:
```javascript
{
  "id": "dl_1672531200000", 
  "url": "spotify:track:4uLU6hMCjMI75M1A2tKUQC",
  "name": "bad guy",
  "artist": "Billie Eilish",
  "type": "track",
  "status": "failed",
  "progress": 45,
  "error": "Track not available in your region",
  "error_code": "GEO_BLOCKED",
  "retry_possible": false
}
```

#### `status`
**Description**: General status update with current downloads  
**Data Structure**:
```javascript
{
  "downloads": [
    // Array of current download objects (same structure as download_progress)
  ],
  "stats": {
    "active_downloads": 2,
    "queued_downloads": 3,
    "completed_today": 15,
    "failed_today": 1
  },
  "server_info": {
    "uptime": 3600,
    "memory_usage": "245MB",
    "cpu_usage": 15.5
  }
}
```

---

## 🔐 Authentication & Security

### **Session Management**
- **Jellyfin Authentication**: Stored in server memory (per-container session)
- **Client State**: Managed via browser localStorage
- **Token Refresh**: Automatic background refresh for Jellyfin tokens
- **Timeout**: 24-hour session timeout for Jellyfin connections

### **CORS Configuration**
```python
# Development Mode (Current)
CORS(app, origins="*", allow_headers="*", supports_credentials=True)

# Production Recommendation
CORS(app, origins=["https://yourdomain.com"], supports_credentials=True)
```

### **Rate Limiting**
- **Spotify API**: 100 requests per minute (enforced by Spotify)
- **Download Concurrent**: 5 simultaneous downloads maximum
- **WebSocket**: No artificial limits (relies on connection stability)

---

## 🔧 Configuration

### **Environment Variables**
```bash
# Required
SPOTIFY_CLIENT_ID=your_spotify_client_id
SPOTIFY_CLIENT_SECRET=your_spotify_client_secret

# Optional Jellyfin Integration  
JELLYFIN_ADDRESS=https://jellyfin.samcloud.ca
JELLYFIN_API_KEY=your_jellyfin_api_key

# Application Settings
HOST=0.0.0.0                    # Bind address
PORT=6544                       # Port number
FLASK_ENV=production            # Environment mode
DEBUG=false                     # Debug mode

# Download Configuration
TRACK_OUTPUT='/data/{artist}/{album} - ({year})/{artist} - {title}.{output-ext}'
ALBUM_OUTPUT='/data/{artist}/{album} - ({year})/{artist} - {title}.{output-ext}'
PLAYLIST_OUTPUT='/data/{list-name}/{artist}/{title}.{output-ext}'
ARTIST_OUTPUT='/data/{artist}/{album} - ({year})/{artist} - {title}.{output-ext}'

# Optional Features
TRIGGER_JELLYFIN_SCAN=True      # Auto-scan after downloads
GENERATE_M3U_PLAYLIST=True      # Create M3U playlists
M3U_PLAYLIST_NAME=samcloud_music
M3U_PLAYLIST_PATH=/data/playlists
```

### **Frontend Configuration (localStorage)**
```javascript
// Jellyfin Server Settings
localStorage.setItem('musicServerType', 'jellyfin');
localStorage.setItem('musicServerUrl', 'https://jellyfin.samcloud.ca');
localStorage.setItem('musicServerUsername', 'your_username');
localStorage.setItem('musicServerPassword', 'your_password');
localStorage.setItem('musicServerConnected', 'true');
localStorage.setItem('musicServerName', 'My Jellyfin Server');

// Application Preferences
localStorage.setItem('theme', 'dark');              // UI theme
localStorage.setItem('autoPlay', 'true');           // Auto-play downloads
localStorage.setItem('downloadQuality', '320');     // Audio quality preference
```

---

## 📊 Response Codes & Error Handling

### **HTTP Status Codes**
- `200` - Success
- `400` - Bad Request (invalid parameters)
- `401` - Unauthorized (authentication required)
- `404` - Not Found (endpoint or resource not found)
- `429` - Too Many Requests (rate limited)
- `500` - Internal Server Error

### **WebSocket Error Codes**
- `CONNECTION_FAILED` - Cannot establish WebSocket connection
- `SEARCH_FAILED` - Spotify search API error
- `DOWNLOAD_FAILED` - SpotDL process error
- `AUTH_FAILED` - Jellyfin authentication error
- `RATE_LIMITED` - API rate limit exceeded
- `GEO_BLOCKED` - Content not available in region
- `FILE_ERROR` - File system or permissions error

### **Error Response Format**
```json
{
  "success": false,
  "error": "Human-readable error message",
  "error_code": "MACHINE_READABLE_CODE",
  "details": {
    "timestamp": "2025-07-01T05:15:00Z",
    "request_id": "req_abc123",
    "additional_info": "Any relevant details"
  }
}
```

---

## 🧪 Testing & Examples

### **cURL Examples**

#### Test Server Health
```bash
curl -v http://localhost:6544/
# Should return HTML content
```

#### Test Jellyfin Authentication
```bash
curl -X POST http://localhost:6544/api/jellyfin/auth \
  -H "Content-Type: application/json" \
  -d '{
    "server_url": "https://jellyfin.samcloud.ca",
    "username": "testuser", 
    "password": "testpass"
  }'
```

#### Test Library Endpoint (after auth)
```bash
curl http://localhost:6544/api/jellyfin/library?type=Audio&limit=5
```

#### Test Download Stats
```bash
curl http://localhost:6544/api/downloads/stats
```

### **JavaScript Examples**

#### WebSocket Connection
```javascript
const socket = io('http://localhost:6544');

socket.on('connect', () => {
  console.log('Connected to SamCloud Music');
  
  // Search for music
  socket.emit('search', {
    query: 'The Beatles',
    type: 'artist',
    limit: 10
  });
});

socket.on('search_results', (data) => {
  console.log('Search results:', data.results);
});

socket.on('download_progress', (data) => {
  console.log(`Download ${data.name}: ${data.progress}%`);
});
```

#### Frontend Integration
```javascript
// Authenticate with Jellyfin
async function authenticateJellyfin(serverUrl, username, password) {
  const response = await fetch('/api/jellyfin/auth', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ server_url: serverUrl, username, password })
  });
  
  const result = await response.json();
  if (result.success) {
    localStorage.setItem('musicServerConnected', 'true');
    return true;
  } else {
    console.error('Auth failed:', result.error);
    return false;
  }
}

// Load library items
async function loadLibrary() {
  const response = await fetch('/api/jellyfin/library?type=Audio&limit=100');
  const result = await response.json();
  
  if (result.success) {
    return result.items;
  } else {
    throw new Error(result.error);
  }
}
```

---

## 📈 Performance & Limits

### **Response Times** (Typical)
- Static files: < 50ms
- API endpoints: < 200ms
- Jellyfin auth: < 1000ms (depends on server)
- Library loading: < 3000ms (depends on library size)
- Search results: < 2000ms (depends on Spotify API)

### **Throughput Limits**
- Concurrent WebSocket connections: 100+ (limited by server resources)
- Simultaneous downloads: 5 (configurable)
- API requests per minute: No artificial limits (bound by external APIs)
- Library items per request: 1000 maximum (pagination recommended)

### **Resource Usage**
- **Memory**: ~200MB base + ~50MB per active download
- **CPU**: Low usage except during active downloads
- **Disk I/O**: High during downloads, low otherwise
- **Network**: Depends on download activity and library browsing

---

**API Documentation Version**: 2.0.0  
**Last Updated**: July 1, 2025  
**Compatibility**: SamCloud Music v2.0.0+
