space.remanso.recording
Schema Diff
+115 -0
Compatibility Analysis
Breaking Changes Detected
5 breaking changes, 17 non-breaking changes.
Breaking Changes (5)
- 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#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 (17)
- 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.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.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.transcript", tgt: "space.remanso.recording#transcript", kind: "ref", name: None }
Migration Guidance
Added Elements
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.language" }AddedVertex { vertex_id: "space.remanso.recording:body.transcript" }
Additional Notes
- 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") }
- 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") }
- 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.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.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
18
"video/mp4",
19
19
"video/webm"
20
20
],
21
21
"maxSize": 50000000,
22
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."
23
23
},
24
24
"title": {
25
25
"type": "string",
26
26
"maxLength": 1000
27
27
},
28
28
"credits": {
29
29
"type": "array",
30
30
"items": {
31
31
"ref": "#credit",
32
32
"type": "ref"
33
33
},
34
34
"maxLength": 64,
35
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
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
+
},
37
94
"createdAt": {
38
95
"type": "string",
39
96
"format": "datetime"
40
97
},
41
98
"recordedAt": {
42
99
"type": "string",
43
100
"format": "datetime",
44
101
"description": "When the audio was originally captured — a past stream's air date, not the upload time."
45
102
},
103
+
"transcript": {
104
+
"ref": "#transcript",
105
+
"type": "ref"
106
+
},
46
107
"durationSec": {
47
108
"type": "integer",
48
109
"description": "Playback length in seconds."
49
110
}
50
111
}
51
112
},
52
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."
53
114
},
54
115
"credit": {
55
116
"type": "object",
56
117
"required": [
57
118
"title",
58
119
"creator",
59
120
"license",
60
121
"licenseUrl",
61
122
"sourceUrl"
62
123
],
63
124
"properties": {
64
125
"title": {
65
126
"type": "string",
66
127
"maxLength": 1000
67
128
},
68
129
"creator": {
69
130
"type": "string",
70
131
"maxLength": 1000
71
132
},
72
133
"license": {
73
134
"type": "string",
74
135
"maxLength": 64,
75
136
"description": "The licence's short id, e.g. \"by\"."
76
137
},
77
138
"sourceUrl": {
78
139
"type": "string",
79
140
"format": "uri",
80
141
"description": "The work's landing page at its provider."
81
142
},
82
143
"licenseUrl": {
83
144
"type": "string",
84
145
"format": "uri"
85
146
}
86
147
},
87
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."
88
203
}
89
204
},
90
205
"$type": "com.atproto.lexicon.schema",
91
206
"lexicon": 1
92
207
}