# Phase 2: Utils Extraction

## Goal

Extract helper functions from types.ts into dedicated utils files.

## Files to Create

### utils/resolvers.ts

Player mode and source resolution:

```typescript
/**
 * Video source and player mode resolvers
 */

import type { VideoSourceUnion, PlayerMode, SimpleStreamSource, StreamSource } from '../types';

/**
 * Determine the appropriate player mode for a given source
 */
export function resolvePlayerMode(source: VideoSourceUnion): PlayerMode {
  switch (source.type) {
    case 'youtube':
    case 'vimeo':
    case 'hls':
    case 'dash':
      return 'vidstack';
    case 'stream':
    case 'blob':
    case 'data-url':
      return 'streaming';
    case 'url':
    default:
      return 'native';
  }
}

/**
 * Check if source is a simple stream (needs context resolution)
 */
export function isSimpleStreamSource(
  source: VideoSourceUnion
): source is SimpleStreamSource {
  return (
    source.type === 'stream' &&
    !('getStreamUrl' in source)
  );
}

/**
 * Resolve simple stream source with context getStreamUrl
 */
export function resolveStreamSource(
  source: SimpleStreamSource,
  getStreamUrl: (streamKey: string) => Promise<string>
): StreamSource {
  return {
    ...source,
    getStreamUrl,
  };
}
```

### utils/fileSource.ts

File content to source conversion:

```typescript
/**
 * File source resolution utilities
 */

import type { VideoSourceUnion, ResolveFileSourceOptions } from '../types';

/**
 * Convert file content to appropriate VideoSource
 */
export function resolveFileSource(options: ResolveFileSourceOptions): VideoSourceUnion {
  const { fileName, content, mimeType } = options;

  // Data URL string
  if (typeof content === 'string' && content.startsWith('data:')) {
    return {
      type: 'data-url',
      dataUrl: content,
      mimeType,
    };
  }

  // Regular URL string
  if (typeof content === 'string') {
    return {
      type: 'url',
      url: content,
      mimeType,
    };
  }

  // ArrayBuffer -> Blob source
  return {
    type: 'blob',
    data: content,
    mimeType: mimeType || guessMimeType(fileName),
    fileName,
  };
}

/**
 * Guess MIME type from file extension
 */
function guessMimeType(fileName: string): string {
  const ext = fileName.split('.').pop()?.toLowerCase();
  const mimeTypes: Record<string, string> = {
    mp4: 'video/mp4',
    webm: 'video/webm',
    ogg: 'video/ogg',
    mov: 'video/quicktime',
    avi: 'video/x-msvideo',
    mkv: 'video/x-matroska',
  };
  return mimeTypes[ext || ''] || 'video/mp4';
}
```

### utils/index.ts

```typescript
/**
 * VideoPlayer utilities - Public API
 */

export {
  resolvePlayerMode,
  isSimpleStreamSource,
  resolveStreamSource,
} from './resolvers';

export { resolveFileSource } from './fileSource';
```
