youtubeinfo-sync 1.0.2

Download YouTube video and channel metadata
# Output Schema Documentation

This document describes the JSON schema for files generated by `youtubeinfo-sync`.

## Output Files

| File | Location | Description |
|------|----------|-------------|
| `videos.json` | `output/feeds/<feed-name>/` | Map of video ID to video object |
| `channels.json` | `output/channels/` | Map of channel ID to channel object |

## videos.json

A map of video IDs to `Video` objects.

```json
{
  "dQw4w9WgXcQ": {
    "kind": "youtube#video",
    "etag": "...",
    "id": "dQw4w9WgXcQ",
    "snippet": { ... },
    "statistics": { ... },
    "contentDetails": { ... },
    "status": { ... }
  }
}
```

### Video Object

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `kind` | string | Yes | Resource type, always `"youtube#video"` |
| `etag` | string | Yes | Entity tag for caching |
| `id` | string | Yes | 11-character YouTube video ID |
| `snippet` | object | No | Basic video metadata |
| `statistics` | object | No | Engagement metrics |
| `contentDetails` | object | No | Technical details |
| `status` | object | No | Publishing status |

### Video Snippet

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `publishedAt` | string | Yes | ISO 8601 publish timestamp |
| `channelId` | string | Yes | Channel ID of uploader |
| `title` | string | Yes | Video title |
| `description` | string | Yes | Video description |
| `thumbnails` | object | Yes | Thumbnail images (see [Thumbnails]#thumbnails) |
| `channelTitle` | string | Yes | Channel name |
| `tags` | array | No | List of video tags |
| `categoryId` | string | Yes | YouTube category ID |
| `liveBroadcastContent` | string | Yes | `"none"`, `"live"`, or `"upcoming"` |
| `defaultLanguage` | string | No | Default language code |
| `localized` | object | No | Localized title/description |
| `defaultAudioLanguage` | string | No | Audio language code |

### Video Statistics

All counts are returned as strings to handle large numbers.

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `viewCount` | string | No | Total view count |
| `likeCount` | string | No | Like count |
| `favoriteCount` | string | No | Favorite count (deprecated, usually "0") |
| `commentCount` | string | No | Comment count |

### Video Content Details

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `duration` | string | Yes | ISO 8601 duration (e.g., `"PT4M12S"`) |
| `dimension` | string | Yes | `"2d"` or `"3d"` |
| `definition` | string | Yes | `"hd"` or `"sd"` |
| `caption` | string | No | `"true"` or `"false"` |
| `licensedContent` | boolean | Yes | Whether content is licensed |
| `regionRestriction` | object | No | Geographic restrictions |
| `projection` | string | Yes | `"rectangular"` or `"360"` |

#### Region Restriction

| Field | Type | Description |
|-------|------|-------------|
| `allowed` | array | ISO 3166-1 alpha-2 country codes where viewable |
| `blocked` | array | ISO 3166-1 alpha-2 country codes where blocked |

### Video Status

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `uploadStatus` | string | Yes | `"uploaded"`, `"processed"`, `"failed"`, `"rejected"`, `"deleted"` |
| `failureReason` | string | No | Reason for upload failure |
| `rejectionReason` | string | No | Reason for rejection |
| `privacyStatus` | string | Yes | `"public"`, `"unlisted"`, `"private"` |
| `publishAt` | string | No | Scheduled publish time (ISO 8601) |
| `license` | string | Yes | `"youtube"` or `"creativeCommon"` |
| `embeddable` | boolean | Yes | Whether embedding is allowed |
| `publicStatsViewable` | boolean | Yes | Whether stats are public |
| `madeForKids` | boolean | No | COPPA designation |

## channels.json

A map of channel IDs to `Channel` objects.

```json
{
  "UCuAXFkgsw1L7xaCfnd5JJOw": {
    "kind": "youtube#channel",
    "etag": "...",
    "id": "UCuAXFkgsw1L7xaCfnd5JJOw",
    "snippet": { ... },
    "statistics": { ... },
    "contentDetails": { ... }
  }
}
```

### Channel Object

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `kind` | string | Yes | Resource type, always `"youtube#channel"` |
| `etag` | string | Yes | Entity tag for caching |
| `id` | string | Yes | YouTube channel ID |
| `snippet` | object | No | Basic channel metadata |
| `statistics` | object | No | Channel metrics |
| `contentDetails` | object | No | Related playlists |

### Channel Snippet

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `title` | string | Yes | Channel name |
| `description` | string | Yes | Channel description |
| `customUrl` | string | No | Custom URL handle (e.g., `"@rickastley"`) |
| `publishedAt` | string | Yes | ISO 8601 channel creation timestamp |
| `thumbnails` | object | Yes | Channel avatar images (see [Thumbnails]#thumbnails) |
| `defaultLanguage` | string | No | Default language code |
| `localized` | object | No | Localized title/description |
| `country` | string | No | ISO 3166-1 alpha-2 country code |

### Channel Statistics

All counts are returned as strings.

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `viewCount` | string | No | Total channel views |
| `subscriberCount` | string | No | Subscriber count (may be rounded) |
| `hiddenSubscriberCount` | boolean | No | Whether subscriber count is hidden |
| `videoCount` | string | No | Number of public videos |

### Channel Content Details

| Field | Type | Description |
|-------|------|-------------|
| `relatedPlaylists` | object | System-generated playlists |

#### Related Playlists

| Field | Type | Description |
|-------|------|-------------|
| `likes` | string | Liked videos playlist ID (deprecated) |
| `uploads` | string | Uploads playlist ID |

## Shared Types

### Thumbnails

Available thumbnail sizes vary by resource.

| Field | Type | Description |
|-------|------|-------------|
| `default` | object | 120x90 pixels |
| `medium` | object | 320x180 pixels |
| `high` | object | 480x360 pixels |
| `standard` | object | 640x480 pixels |
| `maxres` | object | 1280x720 pixels |

Each thumbnail object:

| Field | Type | Description |
|-------|------|-------------|
| `url` | string | Image URL |
| `width` | number | Width in pixels |
| `height` | number | Height in pixels |

### Localized

| Field | Type | Description |
|-------|------|-------------|
| `title` | string | Localized title |
| `description` | string | Localized description |

## Example Output

### videos.json

```json
{
  "dQw4w9WgXcQ": {
    "kind": "youtube#video",
    "etag": "abc123",
    "id": "dQw4w9WgXcQ",
    "snippet": {
      "publishedAt": "2009-10-25T06:57:33Z",
      "channelId": "UCuAXFkgsw1L7xaCfnd5JJOw",
      "title": "Rick Astley - Never Gonna Give You Up (Official Music Video)",
      "description": "The official video for \"Never Gonna Give You Up\"...",
      "thumbnails": {
        "default": {
          "url": "https://i.ytimg.com/vi/dQw4w9WgXcQ/default.jpg",
          "width": 120,
          "height": 90
        },
        "medium": {
          "url": "https://i.ytimg.com/vi/dQw4w9WgXcQ/mqdefault.jpg",
          "width": 320,
          "height": 180
        },
        "high": {
          "url": "https://i.ytimg.com/vi/dQw4w9WgXcQ/hqdefault.jpg",
          "width": 480,
          "height": 360
        }
      },
      "channelTitle": "Rick Astley",
      "tags": ["rick astley", "never gonna give you up", "rickroll"],
      "categoryId": "10",
      "liveBroadcastContent": "none",
      "localized": {
        "title": "Rick Astley - Never Gonna Give You Up (Official Music Video)",
        "description": "The official video for \"Never Gonna Give You Up\"..."
      },
      "defaultAudioLanguage": "en"
    },
    "statistics": {
      "viewCount": "1500000000",
      "likeCount": "15000000",
      "favoriteCount": "0",
      "commentCount": "3000000"
    },
    "contentDetails": {
      "duration": "PT3M33S",
      "dimension": "2d",
      "definition": "hd",
      "caption": "true",
      "licensedContent": true,
      "projection": "rectangular"
    },
    "status": {
      "uploadStatus": "processed",
      "privacyStatus": "public",
      "license": "youtube",
      "embeddable": true,
      "publicStatsViewable": true,
      "madeForKids": false
    }
  }
}
```

### channels.json

```json
{
  "UCuAXFkgsw1L7xaCfnd5JJOw": {
    "kind": "youtube#channel",
    "etag": "xyz789",
    "id": "UCuAXFkgsw1L7xaCfnd5JJOw",
    "snippet": {
      "title": "Rick Astley",
      "description": "The Official Rick Astley YouTube Channel...",
      "customUrl": "@rickastley",
      "publishedAt": "2007-07-20T06:11:42Z",
      "thumbnails": {
        "default": {
          "url": "https://yt3.ggpht.com/...",
          "width": 88,
          "height": 88
        },
        "medium": {
          "url": "https://yt3.ggpht.com/...",
          "width": 240,
          "height": 240
        },
        "high": {
          "url": "https://yt3.ggpht.com/...",
          "width": 800,
          "height": 800
        }
      },
      "localized": {
        "title": "Rick Astley",
        "description": "The Official Rick Astley YouTube Channel..."
      },
      "country": "GB"
    },
    "statistics": {
      "viewCount": "2000000000",
      "subscriberCount": "15000000",
      "hiddenSubscriberCount": false,
      "videoCount": "150"
    },
    "contentDetails": {
      "relatedPlaylists": {
        "likes": "",
        "uploads": "UUuAXFkgsw1L7xaCfnd5JJOw"
      }
    }
  }
}
```

## ISO 8601 Duration Format

Video durations use ISO 8601 duration format:

| Duration | Meaning |
|----------|---------|
| `PT3M33S` | 3 minutes, 33 seconds |
| `PT1H30M` | 1 hour, 30 minutes |
| `PT45S` | 45 seconds |
| `P0D` | Live stream (no fixed duration) |

## YouTube Category IDs

Common category IDs returned in `categoryId`:

| ID | Category |
|----|----------|
| 1 | Film & Animation |
| 2 | Autos & Vehicles |
| 10 | Music |
| 15 | Pets & Animals |
| 17 | Sports |
| 19 | Travel & Events |
| 20 | Gaming |
| 22 | People & Blogs |
| 23 | Comedy |
| 24 | Entertainment |
| 25 | News & Politics |
| 26 | Howto & Style |
| 27 | Education |
| 28 | Science & Technology |
| 29 | Nonprofits & Activism |

## Notes

- All timestamp fields use ISO 8601 format with UTC timezone
- Numeric statistics are returned as strings to prevent integer overflow
- Optional fields may be `null` or omitted entirely
- The `etag` field can be used for conditional requests and caching
- Some fields like `madeForKids` were added in response to COPPA regulations