space.remanso.recording
Schema Diff
+163 -3
Compatibility Analysis
Breaking Changes Detected
10 breaking changes, 28 non-breaking changes.
Breaking Changes (10)
- RequiredEdgeAdded RequiredEdgeAdded { vertex_id: "space.remanso.recording#transcriptSegment", src: "space.remanso.recording#transcriptSegment", tgt: "space.remanso.recording#transcriptSegment.text", kind: "prop", name: Some("text") }
- RequiredEdgeAdded RequiredEdgeAdded { vertex_id: "space.remanso.recording#transcriptSegment", src: "space.remanso.recording#transcriptSegment", tgt: "space.remanso.recording#transcriptSegment.endMs", kind: "prop", name: Some("endMs") }
- RequiredEdgeAdded RequiredEdgeAdded { vertex_id: "space.remanso.recording#transcriptSegment", src: "space.remanso.recording#transcriptSegment", tgt: "space.remanso.recording#transcriptSegment.startMs", kind: "prop", name: Some("startMs") }
- RequiredEdgeAdded RequiredEdgeAdded { vertex_id: "space.remanso.recording#credit", src: "space.remanso.recording#credit", tgt: "space.remanso.recording#credit.licenseUrl", kind: "prop", name: Some("licenseUrl") }
- RequiredEdgeAdded RequiredEdgeAdded { vertex_id: "space.remanso.recording#credit", src: "space.remanso.recording#credit", tgt: "space.remanso.recording#credit.creator", kind: "prop", name: Some("creator") }
- RequiredEdgeAdded RequiredEdgeAdded { vertex_id: "space.remanso.recording#credit", src: "space.remanso.recording#credit", tgt: "space.remanso.recording#credit.license", kind: "prop", name: Some("license") }
- RequiredEdgeAdded RequiredEdgeAdded { vertex_id: "space.remanso.recording#credit", src: "space.remanso.recording#credit", tgt: "space.remanso.recording#credit.sourceUrl", kind: "prop", name: Some("sourceUrl") }
- RequiredEdgeAdded RequiredEdgeAdded { vertex_id: "space.remanso.recording#credit", src: "space.remanso.recording#credit", tgt: "space.remanso.recording#credit.title", kind: "prop", name: Some("title") }
- RequiredEdgeAdded RequiredEdgeAdded { vertex_id: "space.remanso.recording#transcript", src: "space.remanso.recording#transcript", tgt: "space.remanso.recording#transcript.createdAt", kind: "prop", name: Some("createdAt") }
- RequiredEdgeAdded RequiredEdgeAdded { vertex_id: "space.remanso.recording#transcript", src: "space.remanso.recording#transcript", tgt: "space.remanso.recording#transcript.text", kind: "prop", name: Some("text") }
Non-Breaking Changes (28)
- AddedVertex AddedVertex { vertex_id: "space.remanso.recording#credit" }
- AddedVertex AddedVertex { vertex_id: "space.remanso.recording#credit.creator" }
- AddedVertex AddedVertex { vertex_id: "space.remanso.recording#credit.license" }
- AddedVertex AddedVertex { vertex_id: "space.remanso.recording#credit.licenseUrl" }
- AddedVertex AddedVertex { vertex_id: "space.remanso.recording#credit.sourceUrl" }
- AddedVertex AddedVertex { vertex_id: "space.remanso.recording#credit.title" }
- AddedVertex AddedVertex { vertex_id: "space.remanso.recording#transcript" }
- AddedVertex AddedVertex { vertex_id: "space.remanso.recording#transcript.createdAt" }
- AddedVertex AddedVertex { vertex_id: "space.remanso.recording#transcript.segments" }
- AddedVertex AddedVertex { vertex_id: "space.remanso.recording#transcript.segments:items" }
- AddedVertex AddedVertex { vertex_id: "space.remanso.recording#transcript.text" }
- AddedVertex AddedVertex { vertex_id: "space.remanso.recording#transcriptSegment" }
- AddedVertex AddedVertex { vertex_id: "space.remanso.recording#transcriptSegment.endMs" }
- AddedVertex AddedVertex { vertex_id: "space.remanso.recording#transcriptSegment.startMs" }
- AddedVertex AddedVertex { vertex_id: "space.remanso.recording#transcriptSegment.text" }
- AddedVertex AddedVertex { vertex_id: "space.remanso.recording:body.credits" }
- AddedVertex AddedVertex { vertex_id: "space.remanso.recording:body.credits:items" }
- AddedVertex AddedVertex { vertex_id: "space.remanso.recording:body.language" }
- AddedVertex AddedVertex { vertex_id: "space.remanso.recording:body.transcript" }
- AddedEdge AddedEdge { src: "space.remanso.recording#transcript", tgt: "space.remanso.recording#transcript.segments", kind: "prop", name: Some("segments") }
- AddedEdge AddedEdge { src: "space.remanso.recording#transcript.segments", tgt: "space.remanso.recording#transcript.segments:items", kind: "items", name: None }
- AddedEdge AddedEdge { src: "space.remanso.recording#transcript.segments:items", tgt: "space.remanso.recording#transcriptSegment", kind: "ref", name: None }
- AddedEdge AddedEdge { src: "space.remanso.recording:body", tgt: "space.remanso.recording:body.credits", kind: "prop", name: Some("credits") }
- AddedEdge AddedEdge { src: "space.remanso.recording:body", tgt: "space.remanso.recording:body.language", kind: "prop", name: Some("language") }
- AddedEdge AddedEdge { src: "space.remanso.recording:body", tgt: "space.remanso.recording:body.transcript", kind: "prop", name: Some("transcript") }
- AddedEdge AddedEdge { src: "space.remanso.recording:body.credits", tgt: "space.remanso.recording:body.credits:items", kind: "items", name: None }
- AddedEdge AddedEdge { src: "space.remanso.recording:body.credits:items", tgt: "space.remanso.recording#credit", kind: "ref", name: None }
- AddedEdge AddedEdge { src: "space.remanso.recording:body.transcript", tgt: "space.remanso.recording#transcript", kind: "ref", name: None }
Migration Guidance
Added Elements
AddedVertex { vertex_id: "space.remanso.recording#credit" }AddedVertex { vertex_id: "space.remanso.recording#credit.creator" }AddedVertex { vertex_id: "space.remanso.recording#credit.license" }AddedVertex { vertex_id: "space.remanso.recording#credit.licenseUrl" }AddedVertex { vertex_id: "space.remanso.recording#credit.sourceUrl" }AddedVertex { vertex_id: "space.remanso.recording#credit.title" }AddedVertex { vertex_id: "space.remanso.recording#transcript" }AddedVertex { vertex_id: "space.remanso.recording#transcript.createdAt" }AddedVertex { vertex_id: "space.remanso.recording#transcript.segments" }AddedVertex { vertex_id: "space.remanso.recording#transcript.segments:items" }AddedVertex { vertex_id: "space.remanso.recording#transcript.text" }AddedVertex { vertex_id: "space.remanso.recording#transcriptSegment" }AddedVertex { vertex_id: "space.remanso.recording#transcriptSegment.endMs" }AddedVertex { vertex_id: "space.remanso.recording#transcriptSegment.startMs" }AddedVertex { vertex_id: "space.remanso.recording#transcriptSegment.text" }AddedVertex { vertex_id: "space.remanso.recording:body.credits" }AddedVertex { vertex_id: "space.remanso.recording:body.credits:items" }AddedVertex { vertex_id: "space.remanso.recording:body.language" }AddedVertex { vertex_id: "space.remanso.recording:body.transcript" }
Additional Notes
- Breaking: RequiredEdgeAdded { vertex_id: "space.remanso.recording#credit", src: "space.remanso.recording#credit", tgt: "space.remanso.recording#credit.licenseUrl", kind: "prop", name: Some("licenseUrl") }
- Breaking: RequiredEdgeAdded { vertex_id: "space.remanso.recording#credit", src: "space.remanso.recording#credit", tgt: "space.remanso.recording#credit.creator", kind: "prop", name: Some("creator") }
- Breaking: RequiredEdgeAdded { vertex_id: "space.remanso.recording#credit", src: "space.remanso.recording#credit", tgt: "space.remanso.recording#credit.license", kind: "prop", name: Some("license") }
- Breaking: RequiredEdgeAdded { vertex_id: "space.remanso.recording#credit", src: "space.remanso.recording#credit", tgt: "space.remanso.recording#credit.sourceUrl", kind: "prop", name: Some("sourceUrl") }
- Breaking: RequiredEdgeAdded { vertex_id: "space.remanso.recording#credit", src: "space.remanso.recording#credit", tgt: "space.remanso.recording#credit.title", kind: "prop", name: Some("title") }
- Breaking: RequiredEdgeAdded { vertex_id: "space.remanso.recording#transcript", src: "space.remanso.recording#transcript", tgt: "space.remanso.recording#transcript.createdAt", kind: "prop", name: Some("createdAt") }
- Breaking: RequiredEdgeAdded { vertex_id: "space.remanso.recording#transcript", src: "space.remanso.recording#transcript", tgt: "space.remanso.recording#transcript.text", kind: "prop", name: Some("text") }
- Breaking: RequiredEdgeAdded { vertex_id: "space.remanso.recording#transcriptSegment", src: "space.remanso.recording#transcriptSegment", tgt: "space.remanso.recording#transcriptSegment.text", kind: "prop", name: Some("text") }
- Breaking: RequiredEdgeAdded { vertex_id: "space.remanso.recording#transcriptSegment", src: "space.remanso.recording#transcriptSegment", tgt: "space.remanso.recording#transcriptSegment.endMs", kind: "prop", name: Some("endMs") }
- Breaking: RequiredEdgeAdded { vertex_id: "space.remanso.recording#transcriptSegment", src: "space.remanso.recording#transcriptSegment", tgt: "space.remanso.recording#transcriptSegment.startMs", kind: "prop", name: Some("startMs") }
- Non-breaking: AddedEdge { src: "space.remanso.recording#transcript", tgt: "space.remanso.recording#transcript.segments", kind: "prop", name: Some("segments") }
- Non-breaking: AddedEdge { src: "space.remanso.recording#transcript.segments", tgt: "space.remanso.recording#transcript.segments:items", kind: "items", name: None }
- Non-breaking: AddedEdge { src: "space.remanso.recording#transcript.segments:items", tgt: "space.remanso.recording#transcriptSegment", kind: "ref", name: None }
- Non-breaking: AddedEdge { src: "space.remanso.recording:body", tgt: "space.remanso.recording:body.credits", kind: "prop", name: Some("credits") }
- Non-breaking: AddedEdge { src: "space.remanso.recording:body", tgt: "space.remanso.recording:body.language", kind: "prop", name: Some("language") }
- Non-breaking: AddedEdge { src: "space.remanso.recording:body", tgt: "space.remanso.recording:body.transcript", kind: "prop", name: Some("transcript") }
- Non-breaking: AddedEdge { src: "space.remanso.recording:body.credits", tgt: "space.remanso.recording:body.credits:items", kind: "items", name: None }
- Non-breaking: AddedEdge { src: "space.remanso.recording:body.credits:items", tgt: "space.remanso.recording#credit", kind: "ref", name: None }
- Non-breaking: AddedEdge { src: "space.remanso.recording:body.transcript", tgt: "space.remanso.recording#transcript", kind: "ref", name: None }
1
1
{
2
2
"id": "space.remanso.recording",
3
3
"defs": {
4
4
"main": {
5
5
"key": "tid",
6
6
"type": "record",
7
7
"record": {
8
8
"type": "object",
9
9
"required": [
10
10
"audio",
11
11
"createdAt"
12
12
],
13
13
"properties": {
14
14
"audio": {
15
15
"type": "blob",
16
16
"accept": [
17
17
"audio/*",
18
-
"video/mp4"
18
+
"video/mp4",
19
+
"video/webm"
19
20
],
20
21
"maxSize": 50000000,
21
-
"description": "The recording itself. video/mp4 is accepted alongside audio/* because a PDS sniffs the container rather than trusting the upload's Content-Type, and an audio-only MP4 or M4A sniffs as video/mp4."
22
+
"description": "The recording itself. video/mp4 and video/webm are accepted alongside audio/* because a PDS sniffs the container rather than trusting the upload's Content-Type: an audio-only MP4 or M4A sniffs as video/mp4, and a sniffer that reads no further than the EBML magic calls an audio-only WebM video/webm."
22
23
},
23
24
"title": {
24
25
"type": "string",
25
26
"maxLength": 1000
26
27
},
28
+
"credits": {
29
+
"type": "array",
30
+
"items": {
31
+
"ref": "#credit",
32
+
"type": "ref"
33
+
},
34
+
"maxLength": 64,
35
+
"description": "Attribution for openly licensed music mixed into the recording. Only licences that require it are listed — a CC0 track is deliberately absent, because CC0 asks for nothing and an entry here would imply otherwise."
36
+
},
37
+
"language": {
38
+
"type": "string",
39
+
"maxLength": 10,
40
+
"description": "The language spoken in the recording. ISO 639-3, the same code space as space.remanso.note's `language`, so a note and its recording agree on how a language is spelled. A recording whose speech was never identified simply omits this.",
41
+
"knownValues": [
42
+
"afr",
43
+
"ara",
44
+
"aze",
45
+
"bel",
46
+
"ben",
47
+
"bul",
48
+
"cat",
49
+
"ces",
50
+
"ckb",
51
+
"cmn",
52
+
"dan",
53
+
"deu",
54
+
"ell",
55
+
"eng",
56
+
"est",
57
+
"eus",
58
+
"fin",
59
+
"fra",
60
+
"hau",
61
+
"heb",
62
+
"hin",
63
+
"hrv",
64
+
"hun",
65
+
"hye",
66
+
"ind",
67
+
"isl",
68
+
"ita",
69
+
"jpn",
70
+
"kat",
71
+
"kaz",
72
+
"kor",
73
+
"lit",
74
+
"mar",
75
+
"mkd",
76
+
"nld",
77
+
"nob",
78
+
"pes",
79
+
"pol",
80
+
"por",
81
+
"ron",
82
+
"run",
83
+
"rus",
84
+
"slk",
85
+
"spa",
86
+
"srp",
87
+
"swe",
88
+
"tgl",
89
+
"tur",
90
+
"ukr",
91
+
"vie"
92
+
]
93
+
},
27
94
"createdAt": {
28
95
"type": "string",
29
96
"format": "datetime"
30
97
},
31
98
"recordedAt": {
32
99
"type": "string",
33
100
"format": "datetime",
34
101
"description": "When the audio was originally captured — a past stream's air date, not the upload time."
35
102
},
103
+
"transcript": {
104
+
"ref": "#transcript",
105
+
"type": "ref"
106
+
},
36
107
"durationSec": {
37
108
"type": "integer",
38
109
"description": "Playback length in seconds."
39
110
}
40
111
}
41
112
},
42
-
"description": "An audio recording — a past stream, a podcast episode, a voice note — referenced from a Remanso note by at-uri."
113
+
"description": "An audio recording — a past stream, a podcast episode, a voice note. A recording at rkey R is the recording of the space.remanso.note at rkey R in the same repo: one note, at most one recording, paired by convention rather than by a field, so a reader that knows the note's did and rkey reaches the audio with a single getRecord. A recording whose rkey matches no note stands alone and belongs to nobody. Legacy path: a recording is also referenced from a note by at-uri embedded in the note's content."
114
+
},
115
+
"credit": {
116
+
"type": "object",
117
+
"required": [
118
+
"title",
119
+
"creator",
120
+
"license",
121
+
"licenseUrl",
122
+
"sourceUrl"
123
+
],
124
+
"properties": {
125
+
"title": {
126
+
"type": "string",
127
+
"maxLength": 1000
128
+
},
129
+
"creator": {
130
+
"type": "string",
131
+
"maxLength": 1000
132
+
},
133
+
"license": {
134
+
"type": "string",
135
+
"maxLength": 64,
136
+
"description": "The licence's short id, e.g. \"by\"."
137
+
},
138
+
"sourceUrl": {
139
+
"type": "string",
140
+
"format": "uri",
141
+
"description": "The work's landing page at its provider."
142
+
},
143
+
"licenseUrl": {
144
+
"type": "string",
145
+
"format": "uri"
146
+
}
147
+
},
148
+
"description": "One openly licensed work used in the recording, and where its terms live."
149
+
},
150
+
"transcript": {
151
+
"type": "object",
152
+
"required": [
153
+
"text",
154
+
"createdAt"
155
+
],
156
+
"properties": {
157
+
"text": {
158
+
"type": "string",
159
+
"maxLength": 100000,
160
+
"description": "The transcript in reading order, paragraphs separated by a blank line. Equal to `segments` joined the same way, when segments are present."
161
+
},
162
+
"segments": {
163
+
"type": "array",
164
+
"items": {
165
+
"ref": "#transcriptSegment",
166
+
"type": "ref"
167
+
},
168
+
"maxLength": 4096,
169
+
"description": "The transcript cut into timestamped spans, one paragraph each — the granularity a reader scans and seeks by, not the two-second slivers a speech model emits. Absent when the audio yielded no usable timestamps, which happens on very short clips."
170
+
},
171
+
"createdAt": {
172
+
"type": "string",
173
+
"format": "datetime",
174
+
"description": "When this transcript was written, which is later than the recording's own createdAt, and is bumped on every correction."
175
+
}
176
+
},
177
+
"description": "What was said, as text. A recording is published before anything has transcribed it, so audio with no transcript is the normal starting state rather than an incomplete record — which is why this is optional and written by a later putRecord. `text` is the whole transcript in reading order and is always present; `segments` is that same text cut into timestamped spans. The two never disagree: a client renders either one without reconciling them, and a writer that edits one rewrites both."
178
+
},
179
+
"transcriptSegment": {
180
+
"type": "object",
181
+
"required": [
182
+
"startMs",
183
+
"endMs",
184
+
"text"
185
+
],
186
+
"properties": {
187
+
"text": {
188
+
"type": "string",
189
+
"maxLength": 10000
190
+
},
191
+
"endMs": {
192
+
"type": "integer",
193
+
"minimum": 0,
194
+
"description": "Offset from the start of the audio, in milliseconds. Never before `startMs`."
195
+
},
196
+
"startMs": {
197
+
"type": "integer",
198
+
"minimum": 0,
199
+
"description": "Offset from the start of the audio, in milliseconds."
200
+
}
201
+
},
202
+
"description": "One timestamped span of the transcript. Offsets are milliseconds from the start of the audio: the lexicon data model has no float, and rounding to whole seconds would land a seek target after the words the timestamp labels."
43
203
}
44
204
},
45
205
"$type": "com.atproto.lexicon.schema",
46
206
"lexicon": 1
47
207
}