# useMedia

Media playback state and controls.

## Usage

```
import { useMedia } from "@cntrl-pw/sdk";

function MediaPlayer({ bridgeId }: { bridgeId: string }) {
  const { data, control } = useMedia(bridgeId);

if (!data) return <div>No media playing</div>;

return (
    <div>
      <h3>{data.title}</h3>
      <p>{data.artist}</p>

{data.supports_ctrl && (
        <div className="controls">
          <button onClick={() => control.mutate({ action: "previous" })}>⏮</button>
          <button onClick={() => control.mutate({ action: "play_pause" })}> 
            {data.playing ? "⏸" : "▶"}
          </button>
          <button onClick={() => control.mutate({ action: "next" })}>⏭</button>
        </div>
      )}

{data.volume !== null && (
        <input
          type="range"
          min={0}
          max={100}
          value={data.volume}
          onChange={(e) =>
            control.mutate({ action: "set_volume", value: Number(e.target.value) })
          }
        />
      )}
    </div>
  );
}
```

## Return Type

The hook returns `MediaStatus` from the Bridge API:

```
interface MediaStatus {
  status: string;              // Status description
  volume: number | null;       // 0-100 or null if unavailable
  muted: boolean | null;       // Mute state or null if unavailable
  playing: boolean | null;     // Playing state or null if unavailable
  title: string | null;        // Track title
  artist: string | null;       // Artist name
  supports_ctrl: boolean;      // Whether playback control is supported
}

// Control mutation
const { control } = useMedia(bridgeId);
control.mutate(action: MediaAction);

interface MediaAction {
  action: MediaActionType;
  value?: number;              // Required for set_volume
}
```

## Options

### Connection Mode

Control how the hook handles WebSocket connection:

```
// Auto (default) - connects if disconnected
const { data, control } = useMedia(bridgeId);

// Passive - don't trigger connection
const { data, control } = useMedia(bridgeId, { connectionMode: "passive" });

// Eager - connect once, respect manual disconnects
const { data, control } = useMedia(bridgeId, { connectionMode: "eager" });
```

| Mode       | Behavior |
|------------|----------|
| "auto"   | Connects if disconnected. Reconnects on rerenders. |
| "passive"| Never triggers connection. Only uses data if connected. |
| "eager"  | Connects once on mount. Respects manual disconnects. |

## Available Actions

| Action                    | Description                | Value       |
|---------------------------|----------------------------|-------------|
| `play`                    | Start playback             | -           |
| `pause`                   | Pause playback             | -           |
| `play_pause`              | Toggle play/pause          | -           |
| `next`                    | Skip to next track         | -           |
| `previous` / `prev`      | Go to previous track       | -           |
| `set_volume`              | Set volume level           | `0-100`     |
| `volume_up`              | Increase volume            | -           |
| `volume_down`            | Decrease volume            | -           |
| `mute`                    | Mute audio                 | -           |
| `unmute`                  | Unmute audio               | -           |
| `toggle_mute`            | Toggle mute state          | -           |

## Examples

### Volume Slider with Optimistic Updates

Volume changes are optimistic - the UI updates immediately:

```
function VolumeSlider({ bridgeId }: { bridgeId: string }) {
  const { data, control } = useMedia(bridgeId);

if (data?.volume === null) return null;

return (
    <div className="volume">
      <button onClick={() => control.mutate({ action: "toggle_mute" })}> 
        {data?.muted ? "🔇" : "🔊"}
      </button>
      <input
        type="range"
        min={0}
        max={100}
        value={data?.volume ?? 50}
        onChange={(e) =>
          control.mutate({
            action: "set_volume",
            value: Number(e.target.value),
          })
        }
      />
      <span>{data?.volume}%</span>
    </div>
  );
}
```

### Now Playing Card

```
function NowPlaying({ bridgeId }: { bridgeId: string }) {
  const { data } = useMedia(bridgeId);

if (!data?.title) {
    return (
      <div className="now-playing empty">
        <p>Nothing playing</p>
      </div>
    );
  }

return (
    <div className="now-playing">
      <div className="info">
        <h4>{data.title}</h4>
        {data.artist && <p>{data.artist}</p>}
        <p className="status">{data.status}</p>
      </div>
    </div>
  );
}
```

### Full Media Controls

```
function MediaControls({ bridgeId }: { bridgeId: string }) {
  const { data, control } = useMedia(bridgeId);

if (!data) return <div>Loading media...</div>;

// Check if controls are supported
  if (!data.supports_ctrl) {
    return (
      <div className="media-info">
        <p>{data.title ?? "No media"}</p>
        <p className="note">Playback control not available</p>
      </div>
    );
  }

return (
    <div className="media-controls">
      <div className="track-info">
        <h3>{data.title ?? "Unknown"}</h3>
        <p>{data.artist ?? "Unknown artist"}</p>
      </div>

<div className="playback-controls">
        <button onClick={() => control.mutate({ action: "previous" })}>Previous</button>
        <button onClick={() => control.mutate({ action: "play_pause" })}> 
          {data.playing ? "Pause" : "Play"}
        </button>
        <button onClick={() => control.mutate({ action: "next" })}>Next</button>
      </div>

{data.volume !== null && (
        <div className="volume-controls">
          <button onClick={() => control.mutate({ action: "volume_down" })}>-</button>
          <span>{data.volume}%</span>
          <button onClick={() => control.mutate({ action: "volume_up" })}>+</button>
          <button onClick={() => control.mutate({ action: "toggle_mute" })}> 
            {data.muted ? "Unmute" : "Mute"}
          </button>
        </div>
      )}
    </div>
  );
}
```
