1import Foundation
2
3/// A recorder `sync.json` manifest. Each stream names a file and carries the
4/// relative `offsetSeconds` (from the session's clock start) that keeps the
5/// streams aligned. Importing the manifest (or a folder holding it, or the
6/// media files that sit beside it) places each clip at its offset so the whole
7/// multicam session lands in sync.
8struct SyncManifest: Decodable {
9 struct Stream: Decodable {
10 var file: String
11 var offsetSeconds: Double?
12 }
13 var streams: [Stream]
14
15 /// Load a manifest only if `url` is a readable JSON with a streams array.
16 static func load(_ url: URL) -> SyncManifest? {
17 guard let data = try? Data(contentsOf: url),
18 let m = try? JSONDecoder().decode(SyncManifest.self, from: data),
19 !m.streams.isEmpty else { return nil }
20 return m
21 }
22
23 /// filename → offset seconds (missing offsets count as 0).
24 var offsetsByFile: [String: Double] {
25 Dictionary(streams.map { ($0.file, $0.offsetSeconds ?? 0) },
26 uniquingKeysWith: { first, _ in first })
27 }
28}