{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://theamateur.co.uk/schemas/dpl/dpl.edit-export-1.schema.json",
  "title": "DPL assembly-edit export report (dpl.edit-export/1)",
  "description": "What `dpl export-edit --out ...` writes to standard output beside the files it made: the frame rate and timecode the assembly counts in, the files written (an EDL is one list for each video track, split at 999 events), the tracks, the shots that are a slug or a gap and not media, the files to relink with their reel names, the warnings and what the chosen format cannot carry. Every member listed here is always written, or left out when null; nothing else appears.",
  "$comment": "The export itself is OpenTimelineIO JSON, FCPXML 1.10, CMX 3600 EDL or Avid ALE text. This report is deterministic: the same plan, take log and options give the same report and the same files.",
  "type": "object",
  "properties": {
    "format": {
      "type": "string",
      "const": "dpl.edit-export/1"
    },
    "work_id": {
      "type": "string"
    },
    "plan_hash": {
      "description": "SHA-256 of the plan in its standard layout, as readiness reports it.",
      "type": "string",
      "pattern": "^[0-9a-f]{64}$"
    },
    "takes_hash": {
      "description": "SHA-256 of the take log in its standard layout.",
      "type": "string",
      "pattern": "^[0-9a-f]{64}$"
    },
    "edit_format": {
      "$ref": "#/$defs/ExportFormat"
    },
    "frame_rate": {
      "description": "The frame rate the assembly and its timecodes are counted at: 24, 25, 23.976 or 29.97.",
      "type": "string",
      "enum": [
        "24",
        "25",
        "23.976",
        "29.97"
      ]
    },
    "drop_frame": {
      "type": "boolean"
    },
    "timecode_start": {
      "description": "The timecode the assembly starts at.",
      "type": "string",
      "pattern": "^\\d{2}:\\d{2}:\\d{2}[:;]\\d{2}$"
    },
    "media_root": {
      "type": [
        "string",
        "null"
      ]
    },
    "sync_sound": {
      "description": "Whether the sound recorded with the picture is on its own track.",
      "type": "boolean"
    },
    "files": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/ExportedFile"
      }
    },
    "tracks": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/ExportedTrack"
      }
    },
    "duration_ms": {
      "type": "integer",
      "minimum": 0
    },
    "clips": {
      "description": "Clips of media on the picture tracks.",
      "type": "integer",
      "minimum": 0
    },
    "gaps": {
      "description": "The stretches that hold a slug or a gap, not media.",
      "type": "array",
      "items": {
        "$ref": "#/$defs/ExportedGap"
      }
    },
    "media": {
      "description": "The files to relink, with the reel each has in lists and logs.",
      "type": "array",
      "items": {
        "$ref": "#/$defs/ExportedMedia"
      }
    },
    "warnings": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/DiagnosticItem"
      }
    },
    "loses": {
      "description": "What this format cannot carry of the assembly.",
      "type": "array",
      "items": {
        "type": "string"
      }
    }
  },
  "required": [
    "format",
    "work_id",
    "plan_hash",
    "takes_hash",
    "edit_format",
    "frame_rate",
    "drop_frame",
    "timecode_start",
    "sync_sound",
    "files",
    "tracks",
    "duration_ms",
    "clips",
    "gaps",
    "media",
    "warnings",
    "loses"
  ],
  "additionalProperties": false,
  "$defs": {
    "DiagnosticItem": {
      "type": "object",
      "description": "One diagnostic as an agent reads it: what rule, where, what is wrong, and what to change.",
      "properties": {
        "code": {
          "type": "string"
        },
        "severity": {
          "$ref": "#/$defs/PlanSeverity"
        },
        "path": {
          "type": "string"
        },
        "message": {
          "type": "string"
        },
        "fix": {
          "type": "string",
          "pattern": "\\S"
        }
      },
      "required": [
        "code",
        "severity",
        "path",
        "message",
        "fix"
      ],
      "additionalProperties": false
    },
    "ExportFormat": {
      "type": "string",
      "description": "The four formats the assembly can be written in.",
      "enum": [
        "otio",
        "fcpxml",
        "edl",
        "ale"
      ]
    },
    "ExportedFile": {
      "type": "object",
      "description": "A file the export wrote. events counts the events of a list; rows the rows of an ALE; part and of say which piece of a split list it is.",
      "properties": {
        "name": {
          "type": "string"
        },
        "kind": {
          "type": "string"
        },
        "track": {
          "type": [
            "string",
            "null"
          ]
        },
        "events": {
          "type": [
            "integer",
            "null"
          ],
          "minimum": 0
        },
        "rows": {
          "type": [
            "integer",
            "null"
          ],
          "minimum": 0
        },
        "part": {
          "type": [
            "integer",
            "null"
          ],
          "minimum": 1
        },
        "of": {
          "type": [
            "integer",
            "null"
          ],
          "minimum": 1
        },
        "bytes": {
          "type": "integer",
          "minimum": 0
        }
      },
      "required": [
        "name",
        "kind",
        "bytes"
      ],
      "additionalProperties": false
    },
    "ExportedGap": {
      "type": "object",
      "description": "A shot (or line, or tone) that has a slug or a gap and not media, with why.",
      "properties": {
        "shot": {
          "type": [
            "string",
            "null"
          ]
        },
        "track": {
          "type": "string"
        },
        "reason": {
          "$ref": "#/$defs/GapReason"
        },
        "text": {
          "type": "string"
        },
        "start_ms": {
          "type": "integer",
          "minimum": 0
        },
        "end_ms": {
          "type": "integer",
          "minimum": 0
        }
      },
      "required": [
        "track",
        "reason",
        "text",
        "start_ms",
        "end_ms"
      ],
      "additionalProperties": false
    },
    "ExportedMedia": {
      "type": "object",
      "description": "A file the editor must relink: the name in the take log, its reel, and the shots that use it.",
      "properties": {
        "file": {
          "type": "string"
        },
        "reel": {
          "type": "string",
          "pattern": "^[A-Za-z0-9_]{1,8}$"
        },
        "shots": {
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      },
      "required": [
        "file",
        "reel",
        "shots"
      ],
      "additionalProperties": false
    },
    "ExportedTrack": {
      "type": "object",
      "description": "A track of the assembly.",
      "properties": {
        "label": {
          "type": "string"
        },
        "name": {
          "type": "string"
        },
        "kind": {
          "$ref": "#/$defs/TrackKind"
        },
        "role": {
          "$ref": "#/$defs/TrackRole"
        },
        "clips": {
          "type": "integer",
          "minimum": 0
        },
        "gaps": {
          "type": "integer",
          "minimum": 0
        }
      },
      "required": [
        "label",
        "name",
        "kind",
        "role",
        "clips",
        "gaps"
      ],
      "additionalProperties": false
    },
    "GapReason": {
      "type": "string",
      "description": "Why a stretch of the timeline holds no media. MissingShot and NoFile are slugs for a shot that cannot be cut yet; NotFilmed is a shot made in post (a graphic, a still); Unrecorded is sound that was called for and not logged; ShortTake is what is left of a slot when the take ran shorter than the plan; Spacing is only the time between two clips.",
      "enum": [
        "spacing",
        "missing_shot",
        "no_file",
        "not_filmed",
        "unrecorded",
        "short_take"
      ]
    },
    "PlanSeverity": {
      "type": "string",
      "enum": [
        "error",
        "warning"
      ]
    },
    "TrackKind": {
      "type": "string",
      "enum": [
        "video",
        "audio"
      ]
    },
    "TrackRole": {
      "type": "string",
      "description": "What a track carries: the picture, the sound recorded with the picture, the narration, or room tone.",
      "enum": [
        "picture",
        "sync_sound",
        "narration",
        "room_tone"
      ]
    }
  }
}
