typed-ffmpeg-compatible 3.0.2a0__py3-none-any.whl → 3.2.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. typed_ffmpeg/__init__.py +2 -1
  2. typed_ffmpeg/_version.py +21 -0
  3. typed_ffmpeg/compile/compile_cli.py +43 -35
  4. typed_ffmpeg/compile/compile_python.py +3 -4
  5. typed_ffmpeg/ffprobe/__init__.py +0 -0
  6. typed_ffmpeg/ffprobe/parse.py +133 -0
  7. typed_ffmpeg/ffprobe/probe.py +272 -0
  8. typed_ffmpeg/ffprobe/schema.py +455 -0
  9. typed_ffmpeg/ffprobe/xml2json.py +70 -0
  10. {typed_ffmpeg_compatible-3.0.2a0.dist-info → typed_ffmpeg_compatible-3.2.2.dist-info}/METADATA +36 -17
  11. typed_ffmpeg_compatible-3.2.2.dist-info/RECORD +58 -0
  12. {typed_ffmpeg_compatible-3.0.2a0.dist-info → typed_ffmpeg_compatible-3.2.2.dist-info}/WHEEL +2 -1
  13. typed_ffmpeg_compatible-3.2.2.dist-info/entry_points.txt +2 -0
  14. typed_ffmpeg_compatible-3.2.2.dist-info/top_level.txt +1 -0
  15. typed_ffmpeg/common/cache/.gitignore +0 -3
  16. typed_ffmpeg/common/cache/FFMpegFilterManuallyDefined/acrossover.json +0 -6
  17. typed_ffmpeg/common/cache/FFMpegFilterManuallyDefined/afir.json +0 -9
  18. typed_ffmpeg/common/cache/FFMpegFilterManuallyDefined/aiir.json +0 -6
  19. typed_ffmpeg/common/cache/FFMpegFilterManuallyDefined/ainterleave.json +0 -9
  20. typed_ffmpeg/common/cache/FFMpegFilterManuallyDefined/amerge.json +0 -9
  21. typed_ffmpeg/common/cache/FFMpegFilterManuallyDefined/amix.json +0 -9
  22. typed_ffmpeg/common/cache/FFMpegFilterManuallyDefined/amovie.json +0 -6
  23. typed_ffmpeg/common/cache/FFMpegFilterManuallyDefined/anequalizer.json +0 -6
  24. typed_ffmpeg/common/cache/FFMpegFilterManuallyDefined/aphasemeter.json +0 -6
  25. typed_ffmpeg/common/cache/FFMpegFilterManuallyDefined/asegment.json +0 -6
  26. typed_ffmpeg/common/cache/FFMpegFilterManuallyDefined/aselect.json +0 -6
  27. typed_ffmpeg/common/cache/FFMpegFilterManuallyDefined/asplit.json +0 -6
  28. typed_ffmpeg/common/cache/FFMpegFilterManuallyDefined/astreamselect.json +0 -9
  29. typed_ffmpeg/common/cache/FFMpegFilterManuallyDefined/bm3d.json +0 -6
  30. typed_ffmpeg/common/cache/FFMpegFilterManuallyDefined/channelsplit.json +0 -6
  31. typed_ffmpeg/common/cache/FFMpegFilterManuallyDefined/concat.json +0 -9
  32. typed_ffmpeg/common/cache/FFMpegFilterManuallyDefined/decimate.json +0 -6
  33. typed_ffmpeg/common/cache/FFMpegFilterManuallyDefined/ebur128.json +0 -6
  34. typed_ffmpeg/common/cache/FFMpegFilterManuallyDefined/extractplanes.json +0 -6
  35. typed_ffmpeg/common/cache/FFMpegFilterManuallyDefined/fieldmatch.json +0 -6
  36. typed_ffmpeg/common/cache/FFMpegFilterManuallyDefined/guided.json +0 -6
  37. typed_ffmpeg/common/cache/FFMpegFilterManuallyDefined/headphone.json +0 -6
  38. typed_ffmpeg/common/cache/FFMpegFilterManuallyDefined/hstack.json +0 -9
  39. typed_ffmpeg/common/cache/FFMpegFilterManuallyDefined/interleave.json +0 -9
  40. typed_ffmpeg/common/cache/FFMpegFilterManuallyDefined/join.json +0 -9
  41. typed_ffmpeg/common/cache/FFMpegFilterManuallyDefined/libplacebo.json +0 -9
  42. typed_ffmpeg/common/cache/FFMpegFilterManuallyDefined/limitdiff.json +0 -6
  43. typed_ffmpeg/common/cache/FFMpegFilterManuallyDefined/mergeplanes.json +0 -6
  44. typed_ffmpeg/common/cache/FFMpegFilterManuallyDefined/mix.json +0 -9
  45. typed_ffmpeg/common/cache/FFMpegFilterManuallyDefined/movie.json +0 -6
  46. typed_ffmpeg/common/cache/FFMpegFilterManuallyDefined/premultiply.json +0 -6
  47. typed_ffmpeg/common/cache/FFMpegFilterManuallyDefined/segment.json +0 -6
  48. typed_ffmpeg/common/cache/FFMpegFilterManuallyDefined/select.json +0 -6
  49. typed_ffmpeg/common/cache/FFMpegFilterManuallyDefined/signature.json +0 -9
  50. typed_ffmpeg/common/cache/FFMpegFilterManuallyDefined/split.json +0 -6
  51. typed_ffmpeg/common/cache/FFMpegFilterManuallyDefined/streamselect.json +0 -9
  52. typed_ffmpeg/common/cache/FFMpegFilterManuallyDefined/unpremultiply.json +0 -6
  53. typed_ffmpeg/common/cache/FFMpegFilterManuallyDefined/vstack.json +0 -9
  54. typed_ffmpeg/common/cache/FFMpegFilterManuallyDefined/xmedian.json +0 -9
  55. typed_ffmpeg/common/cache/FFMpegFilterManuallyDefined/xstack.json +0 -9
  56. typed_ffmpeg/common/cache/list/filters.json +0 -90747
  57. typed_ffmpeg/common/cache/list/options.json +0 -1694
  58. typed_ffmpeg/probe.py +0 -75
  59. typed_ffmpeg_compatible-3.0.2a0.dist-info/RECORD +0 -95
  60. typed_ffmpeg_compatible-3.0.2a0.dist-info/entry_points.txt +0 -3
  61. {typed_ffmpeg_compatible-3.0.2a0.dist-info → typed_ffmpeg_compatible-3.2.2.dist-info/licenses}/LICENSE +0 -0
@@ -0,0 +1,455 @@
1
+ #!/usr/bin/env python3
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Optional
5
+
6
+
7
+ @dataclass(kw_only=True, frozen=True)
8
+ class ffprobeType:
9
+ program_version: Optional["programVersionType"] = None
10
+ library_versions: Optional["libraryVersionsType"] = None
11
+ pixel_formats: Optional["pixelFormatsType"] = None
12
+ packets: Optional["packetsType"] = None
13
+ frames: Optional["framesType"] = None
14
+ packets_and_frames: Optional["packetsAndFramesType"] = None
15
+ programs: Optional["programsType"] = None
16
+ streams: Optional["streamsType"] = None
17
+ chapters: Optional["chaptersType"] = None
18
+ format: Optional["formatType"] = None
19
+ error: Optional["errorType"] = None
20
+
21
+
22
+ @dataclass(kw_only=True, frozen=True)
23
+ class packetsType:
24
+ packet: tuple["packetType", ...] | None = None
25
+
26
+
27
+ @dataclass(kw_only=True, frozen=True)
28
+ class framesType:
29
+ frame: tuple["frameType", ...] | None = None
30
+ subtitle: tuple["subtitleType", ...] | None = None
31
+
32
+
33
+ @dataclass(kw_only=True, frozen=True)
34
+ class packetsAndFramesType:
35
+ packet: tuple["packetType", ...] | None = None
36
+ frame: tuple["frameType", ...] | None = None
37
+ subtitle: tuple["subtitleType", ...] | None = None
38
+
39
+
40
+ @dataclass(kw_only=True, frozen=True)
41
+ class tagsType:
42
+ tag: tuple["tagType", ...] | None = None
43
+
44
+
45
+ @dataclass(kw_only=True, frozen=True)
46
+ class packetType:
47
+ tags: Optional["tagsType"] = None
48
+ side_data_list: Optional["packetSideDataListType"] = None
49
+ codec_type: str | None = None
50
+ stream_index: int | None = None
51
+ pts: int | None = None
52
+ pts_time: float | None = None
53
+ dts: int | None = None
54
+ dts_time: float | None = None
55
+ duration: int | None = None
56
+ duration_time: float | None = None
57
+ size: int | None = None
58
+ pos: int | None = None
59
+ flags: str | None = None
60
+ data: str | None = None
61
+ data_hash: str | None = None
62
+
63
+
64
+ @dataclass(kw_only=True, frozen=True)
65
+ class packetSideDataListType:
66
+ side_data: tuple["packetSideDataType", ...] | None = None
67
+
68
+
69
+ @dataclass(kw_only=True, frozen=True)
70
+ class packetSideDataType:
71
+ side_datum: tuple["packetSideDatumType", ...] | None = None
72
+ type: str | None = None
73
+
74
+
75
+ @dataclass(kw_only=True, frozen=True)
76
+ class packetSideDatumType:
77
+ key: str | None = None
78
+ value: str | None = None
79
+
80
+
81
+ @dataclass(kw_only=True, frozen=True)
82
+ class frameType:
83
+ tags: Optional["tagsType"] = None
84
+ logs: Optional["logsType"] = None
85
+ side_data_list: Optional["frameSideDataListType"] = None
86
+ media_type: str | None = None
87
+ stream_index: int | None = None
88
+ key_frame: int | None = None
89
+ pts: int | None = None
90
+ pts_time: float | None = None
91
+ pkt_dts: int | None = None
92
+ pkt_dts_time: float | None = None
93
+ best_effort_timestamp: int | None = None
94
+ best_effort_timestamp_time: float | None = None
95
+ pkt_duration: int | None = None
96
+ pkt_duration_time: float | None = None
97
+ duration: int | None = None
98
+ duration_time: float | None = None
99
+ pkt_pos: int | None = None
100
+ pkt_size: int | None = None
101
+ sample_fmt: str | None = None
102
+ nb_samples: int | None = None
103
+ channels: int | None = None
104
+ channel_layout: str | None = None
105
+ width: int | None = None
106
+ height: int | None = None
107
+ crop_top: int | None = None
108
+ crop_bottom: int | None = None
109
+ crop_left: int | None = None
110
+ crop_right: int | None = None
111
+ pix_fmt: str | None = None
112
+ sample_aspect_ratio: str | None = None
113
+ pict_type: str | None = None
114
+ coded_picture_number: int | None = None
115
+ display_picture_number: int | None = None
116
+ interlaced_frame: int | None = None
117
+ top_field_first: int | None = None
118
+ repeat_pict: int | None = None
119
+ color_range: str | None = None
120
+ color_space: str | None = None
121
+ color_primaries: str | None = None
122
+ color_transfer: str | None = None
123
+ chroma_location: str | None = None
124
+
125
+
126
+ @dataclass(kw_only=True, frozen=True)
127
+ class logsType:
128
+ log: tuple["logType", ...] | None = None
129
+
130
+
131
+ @dataclass(kw_only=True, frozen=True)
132
+ class logType:
133
+ context: str | None = None
134
+ level: int | None = None
135
+ category: int | None = None
136
+ parent_context: str | None = None
137
+ parent_category: int | None = None
138
+ message: str | None = None
139
+
140
+
141
+ @dataclass(kw_only=True, frozen=True)
142
+ class frameSideDataListType:
143
+ side_data: tuple["frameSideDataType", ...] | None = None
144
+
145
+
146
+ @dataclass(kw_only=True, frozen=True)
147
+ class frameSideDataType:
148
+ timecodes: Optional["frameSideDataTimecodeList"] = None
149
+ components: Optional["frameSideDataComponentList"] = None
150
+ side_datum: tuple["frameSideDatumType", ...] | None = None
151
+ side_data_type: str | None = None
152
+ side_data_size: int | None = None
153
+ timecode: str | None = None
154
+
155
+
156
+ @dataclass(kw_only=True, frozen=True)
157
+ class frameSideDatumType:
158
+ key: str | None = None
159
+ value: str | None = None
160
+
161
+
162
+ @dataclass(kw_only=True, frozen=True)
163
+ class frameSideDataTimecodeList:
164
+ timecode: tuple["frameSideDataTimecodeType", ...] | None = None
165
+
166
+
167
+ @dataclass(kw_only=True, frozen=True)
168
+ class frameSideDataTimecodeType:
169
+ value: str | None = None
170
+
171
+
172
+ @dataclass(kw_only=True, frozen=True)
173
+ class frameSideDataComponentList:
174
+ component: tuple["frameSideDataComponentType", ...] | None = None
175
+
176
+
177
+ @dataclass(kw_only=True, frozen=True)
178
+ class frameSideDataComponentType:
179
+ pieces: Optional["frameSideDataPieceList"] = None
180
+ side_datum: tuple["frameSideDatumType", ...] | None = None
181
+
182
+
183
+ @dataclass(kw_only=True, frozen=True)
184
+ class frameSideDataPieceList:
185
+ piece: tuple["frameSideDataPieceType", ...] | None = None
186
+
187
+
188
+ @dataclass(kw_only=True, frozen=True)
189
+ class frameSideDataPieceType:
190
+ side_datum: tuple["frameSideDatumType", ...] | None = None
191
+
192
+
193
+ @dataclass(kw_only=True, frozen=True)
194
+ class subtitleType:
195
+ media_type: str | None = None
196
+ pts: int | None = None
197
+ pts_time: float | None = None
198
+ format: int | None = None
199
+ start_display_time: int | None = None
200
+ end_display_time: int | None = None
201
+ num_rects: int | None = None
202
+
203
+
204
+ @dataclass(kw_only=True, frozen=True)
205
+ class streamsType:
206
+ stream: tuple["streamType", ...] | None = None
207
+
208
+
209
+ @dataclass(kw_only=True, frozen=True)
210
+ class programsType:
211
+ program: tuple["programType", ...] | None = None
212
+
213
+
214
+ @dataclass(kw_only=True, frozen=True)
215
+ class streamDispositionType:
216
+ default: int | None = None
217
+ dub: int | None = None
218
+ original: int | None = None
219
+ comment: int | None = None
220
+ lyrics: int | None = None
221
+ karaoke: int | None = None
222
+ forced: int | None = None
223
+ hearing_impaired: int | None = None
224
+ visual_impaired: int | None = None
225
+ clean_effects: int | None = None
226
+ attached_pic: int | None = None
227
+ timed_thumbnails: int | None = None
228
+ non_diegetic: int | None = None
229
+ captions: int | None = None
230
+ descriptions: int | None = None
231
+ metadata: int | None = None
232
+ dependent: int | None = None
233
+ still_image: int | None = None
234
+
235
+
236
+ @dataclass(kw_only=True, frozen=True)
237
+ class streamType:
238
+ disposition: Optional["streamDispositionType"] = None
239
+ tags: Optional["tagsType"] = None
240
+ side_data_list: Optional["packetSideDataListType"] = None
241
+ index: int | None = None
242
+ codec_name: str | None = None
243
+ codec_long_name: str | None = None
244
+ profile: str | None = None
245
+ codec_type: str | None = None
246
+ codec_tag: str | None = None
247
+ codec_tag_string: str | None = None
248
+ extradata: str | None = None
249
+ extradata_size: int | None = None
250
+ extradata_hash: str | None = None
251
+ width: int | None = None
252
+ height: int | None = None
253
+ coded_width: int | None = None
254
+ coded_height: int | None = None
255
+ closed_captions: bool | None = None
256
+ film_grain: bool | None = None
257
+ has_b_frames: int | None = None
258
+ sample_aspect_ratio: str | None = None
259
+ display_aspect_ratio: str | None = None
260
+ pix_fmt: str | None = None
261
+ level: int | None = None
262
+ color_range: str | None = None
263
+ color_space: str | None = None
264
+ color_transfer: str | None = None
265
+ color_primaries: str | None = None
266
+ chroma_location: str | None = None
267
+ field_order: str | None = None
268
+ refs: int | None = None
269
+ sample_fmt: str | None = None
270
+ sample_rate: int | None = None
271
+ channels: int | None = None
272
+ channel_layout: str | None = None
273
+ bits_per_sample: int | None = None
274
+ initial_padding: int | None = None
275
+ id: str | None = None
276
+ r_frame_rate: str | None = None
277
+ avg_frame_rate: str | None = None
278
+ time_base: str | None = None
279
+ start_pts: int | None = None
280
+ start_time: float | None = None
281
+ duration_ts: int | None = None
282
+ duration: float | None = None
283
+ bit_rate: int | None = None
284
+ max_bit_rate: int | None = None
285
+ bits_per_raw_sample: int | None = None
286
+ nb_frames: int | None = None
287
+ nb_read_frames: int | None = None
288
+ nb_read_packets: int | None = None
289
+
290
+
291
+ @dataclass(kw_only=True, frozen=True)
292
+ class programType:
293
+ tags: Optional["tagsType"] = None
294
+ streams: Optional["streamsType"] = None
295
+ program_id: int | None = None
296
+ program_num: int | None = None
297
+ nb_streams: int | None = None
298
+ pmt_pid: int | None = None
299
+ pcr_pid: int | None = None
300
+
301
+
302
+ @dataclass(kw_only=True, frozen=True)
303
+ class formatType:
304
+ tags: Optional["tagsType"] = None
305
+ filename: str | None = None
306
+ nb_streams: int | None = None
307
+ nb_programs: int | None = None
308
+ nb_stream_groups: int | None = None
309
+ format_name: str | None = None
310
+ format_long_name: str | None = None
311
+ start_time: float | None = None
312
+ duration: float | None = None
313
+ size: int | None = None
314
+ bit_rate: int | None = None
315
+ probe_score: int | None = None
316
+
317
+
318
+ @dataclass(kw_only=True, frozen=True)
319
+ class tagType:
320
+ key: str | None = None
321
+ value: str | None = None
322
+
323
+
324
+ @dataclass(kw_only=True, frozen=True)
325
+ class errorType:
326
+ code: int | None = None
327
+ string: str | None = None
328
+
329
+
330
+ @dataclass(kw_only=True, frozen=True)
331
+ class programVersionType:
332
+ version: str | None = None
333
+ copyright: str | None = None
334
+ build_date: str | None = None
335
+ build_time: str | None = None
336
+ compiler_ident: str | None = None
337
+ configuration: str | None = None
338
+
339
+
340
+ @dataclass(kw_only=True, frozen=True)
341
+ class chaptersType:
342
+ chapter: tuple["chapterType", ...] | None = None
343
+
344
+
345
+ @dataclass(kw_only=True, frozen=True)
346
+ class chapterType:
347
+ tags: tuple["tagsType", ...] | None = None
348
+ id: int | None = None
349
+ time_base: str | None = None
350
+ start: int | None = None
351
+ start_time: float | None = None
352
+ end: int | None = None
353
+ end_time: float | None = None
354
+
355
+
356
+ @dataclass(kw_only=True, frozen=True)
357
+ class libraryVersionType:
358
+ name: str | None = None
359
+ major: int | None = None
360
+ minor: int | None = None
361
+ micro: int | None = None
362
+ version: int | None = None
363
+ ident: str | None = None
364
+
365
+
366
+ @dataclass(kw_only=True, frozen=True)
367
+ class libraryVersionsType:
368
+ library_version: tuple["libraryVersionType", ...] | None = None
369
+
370
+
371
+ @dataclass(kw_only=True, frozen=True)
372
+ class pixelFormatFlagsType:
373
+ big_endian: int | None = None
374
+ palette: int | None = None
375
+ bitstream: int | None = None
376
+ hwaccel: int | None = None
377
+ planar: int | None = None
378
+ rgb: int | None = None
379
+ alpha: int | None = None
380
+
381
+
382
+ @dataclass(kw_only=True, frozen=True)
383
+ class pixelFormatComponentType:
384
+ index: int | None = None
385
+ bit_depth: int | None = None
386
+
387
+
388
+ @dataclass(kw_only=True, frozen=True)
389
+ class pixelFormatComponentsType:
390
+ component: tuple["pixelFormatComponentType", ...] | None = None
391
+
392
+
393
+ @dataclass(kw_only=True, frozen=True)
394
+ class pixelFormatType:
395
+ flags: Optional["pixelFormatFlagsType"] = None
396
+ components: Optional["pixelFormatComponentsType"] = None
397
+ name: str | None = None
398
+ nb_components: int | None = None
399
+ log2_chroma_w: int | None = None
400
+ log2_chroma_h: int | None = None
401
+ bits_per_pixel: int | None = None
402
+
403
+
404
+ @dataclass(kw_only=True, frozen=True)
405
+ class pixelFormatsType:
406
+ pixel_format: tuple["pixelFormatType", ...] | None = None
407
+
408
+
409
+ registered_types = {
410
+ "None": None,
411
+ "bool": bool,
412
+ "chapterType": chapterType,
413
+ "chaptersType": chaptersType,
414
+ "errorType": errorType,
415
+ "ffprobeType": ffprobeType,
416
+ "float": float,
417
+ "formatType": formatType,
418
+ "frameSideDataComponentList": frameSideDataComponentList,
419
+ "frameSideDataComponentType": frameSideDataComponentType,
420
+ "frameSideDataListType": frameSideDataListType,
421
+ "frameSideDataPieceList": frameSideDataPieceList,
422
+ "frameSideDataPieceType": frameSideDataPieceType,
423
+ "frameSideDataTimecodeList": frameSideDataTimecodeList,
424
+ "frameSideDataTimecodeType": frameSideDataTimecodeType,
425
+ "frameSideDataType": frameSideDataType,
426
+ "frameSideDatumType": frameSideDatumType,
427
+ "frameType": frameType,
428
+ "framesType": framesType,
429
+ "int": int,
430
+ "libraryVersionType": libraryVersionType,
431
+ "libraryVersionsType": libraryVersionsType,
432
+ "logType": logType,
433
+ "logsType": logsType,
434
+ "packetSideDataListType": packetSideDataListType,
435
+ "packetSideDataType": packetSideDataType,
436
+ "packetSideDatumType": packetSideDatumType,
437
+ "packetType": packetType,
438
+ "packetsAndFramesType": packetsAndFramesType,
439
+ "packetsType": packetsType,
440
+ "pixelFormatComponentType": pixelFormatComponentType,
441
+ "pixelFormatComponentsType": pixelFormatComponentsType,
442
+ "pixelFormatFlagsType": pixelFormatFlagsType,
443
+ "pixelFormatType": pixelFormatType,
444
+ "pixelFormatsType": pixelFormatsType,
445
+ "programType": programType,
446
+ "programVersionType": programVersionType,
447
+ "programsType": programsType,
448
+ "str": str,
449
+ "streamDispositionType": streamDispositionType,
450
+ "streamType": streamType,
451
+ "streamsType": streamsType,
452
+ "subtitleType": subtitleType,
453
+ "tagType": tagType,
454
+ "tagsType": tagsType,
455
+ }
@@ -0,0 +1,70 @@
1
+ import json
2
+ import xml.etree.ElementTree as ET
3
+ from typing import Any, cast
4
+
5
+
6
+ def xml_to_dict(element: ET.Element) -> dict[str, Any]:
7
+ """Convert an XML Element to a dictionary representation.
8
+
9
+ This function recursively converts an XML Element and its children into a nested
10
+ dictionary structure. Attributes are preserved as dictionary keys, and text content
11
+ is stored under the 'text' key when present.
12
+
13
+ Args:
14
+ element: The XML Element to convert.
15
+
16
+ Returns:
17
+ A dictionary representation of the XML Element.
18
+ - Attributes are stored as key-value pairs
19
+ - Child elements are stored as nested dictionaries
20
+ - Multiple elements with the same tag are stored as lists
21
+ - Text content is stored under the 'text' key
22
+ """
23
+ node: dict[str, Any] = {}
24
+ if element.attrib:
25
+ node.update(element.attrib)
26
+ children: list[ET.Element] = list(element)
27
+ if children:
28
+ child_dict: dict[str, dict[str, Any] | list[dict[str, Any]]] = {}
29
+ for child in children:
30
+ child_result = xml_to_dict(child)
31
+ if child.tag in child_dict:
32
+ current = child_dict[child.tag]
33
+ if not isinstance(current, list):
34
+ child_dict[child.tag] = [current]
35
+ cast(list[dict[str, Any]], child_dict[child.tag]).append(child_result)
36
+ else:
37
+ child_dict[child.tag] = child_result
38
+ node.update(child_dict)
39
+ text = (element.text or "").strip()
40
+ if text and (not children or node == {}):
41
+ node["text"] = text
42
+ return node
43
+
44
+
45
+ def xml_string_to_json(xml_string: str) -> str:
46
+ """Convert an XML string to a JSON string.
47
+
48
+ This function takes an XML string, parses it into an ElementTree structure,
49
+ converts it to a dictionary using xml_to_dict, and then serializes it to a JSON string.
50
+
51
+ Args:
52
+ xml_string: A string containing valid XML data.
53
+
54
+ Returns:
55
+ A JSON string representation of the XML data, with the root element's
56
+ tag as the top-level key and the converted dictionary as its value.
57
+
58
+ Example:
59
+ >>> xml = "<root><item>value</item></root>"
60
+ >>> xml_string_to_json(xml)
61
+ '{
62
+ "root": {
63
+ "item": {
64
+ "text": "value"
65
+ }
66
+ }
67
+ }'
68
+ """
69
+ root = ET.fromstring(xml_string)
70
+ return json.dumps({root.tag: xml_to_dict(root)}, indent=2)
@@ -1,15 +1,13 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: typed-ffmpeg-compatible
3
- Version: 3.0.2a0
3
+ Version: 3.2.2
4
4
  Summary: Modern Python FFmpeg wrappers offer comprehensive support for complex filters, complete with detailed typing and documentation.
5
- Home-page: https://livingbio.github.io/typed-ffmpeg/
6
- License: MIT
5
+ Author-email: lucemia <lucemia@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://livingbio.github.io/typed-ffmpeg/
8
+ Project-URL: Repository, https://github.com/livingbio/typed-ffmpeg
7
9
  Keywords: ffmpeg,video,audio,multimedia,filter
8
- Author: lucemia
9
- Author-email: lucemia@gmail.com
10
- Requires-Python: >=3.10,<4.0
11
10
  Classifier: Intended Audience :: Developers
12
- Classifier: License :: OSI Approved :: MIT License
13
11
  Classifier: Natural Language :: English
14
12
  Classifier: Operating System :: OS Independent
15
13
  Classifier: Programming Language :: Python
@@ -17,15 +15,18 @@ Classifier: Programming Language :: Python :: 3
17
15
  Classifier: Programming Language :: Python :: 3.10
18
16
  Classifier: Programming Language :: Python :: 3.11
19
17
  Classifier: Programming Language :: Python :: 3.12
20
- Classifier: Topic :: Multimedia :: Sound/Audio
18
+ Classifier: Programming Language :: Python :: 3.13
21
19
  Classifier: Topic :: Multimedia :: Video
20
+ Classifier: Topic :: Multimedia :: Sound/Audio
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
22
  Classifier: Topic :: Software Development :: Libraries
23
23
  Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
24
- Classifier: Topic :: Software Development :: Libraries :: Python Modules
25
- Provides-Extra: graph
26
- Requires-Dist: graphviz ; extra == "graph"
27
- Project-URL: Repository, https://github.com/livingbio/typed-ffmpeg
24
+ Requires-Python: >=3.10
28
25
  Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+ Provides-Extra: graph
28
+ Requires-Dist: graphviz; extra == "graph"
29
+ Dynamic: license-file
29
30
 
30
31
  ## typed-ffmpeg
31
32
 
@@ -44,6 +45,7 @@ Description-Content-Type: text/markdown
44
45
  - [Installation](#installation)
45
46
  - [Quick Usage](#quick-usage)
46
47
  - [Documentation](https://livingbio.github.io/typed-ffmpeg/)
48
+ - [Interactive Playground](#interactive-playground)
47
49
  - [Acknowledgements](#acknowledgements)
48
50
 
49
51
  ---
@@ -63,6 +65,7 @@ Description-Content-Type: text/markdown
63
65
  - **Validation and Auto-correction:** Assists in identifying and fixing errors within filter graphs.
64
66
  - **Input and Output Options Support:** Provide a more comprehensive interface for input and output options, including support for additional codecs and formats.
65
67
  - **Partial Evaluation:** Enhance the flexibility of filter graphs by enabling partial evaluation, allowing for modular construction and reuse.
68
+ - **Media File Analysis:** Built-in support for analyzing media files using FFmpeg's ffprobe utility, providing detailed metadata extraction with both dictionary and dataclass interfaces.
66
69
 
67
70
  ### Planned Features
68
71
 
@@ -101,12 +104,14 @@ Note: This requires Graphviz to be installed on your system.
101
104
 
102
105
  Here's how to quickly start using `typed-ffmpeg`:
103
106
 
104
-
105
-
106
-
107
107
  ```python
108
108
  import ffmpeg
109
109
 
110
+ # Analyze a media file
111
+ info = ffmpeg.probe("video.mp4")
112
+ print(f"Duration: {float(info['format']['duration']):.2f} seconds")
113
+ print(f"Streams: {len(info['streams'])}")
114
+
110
115
  # Flip video horizontally and output
111
116
  f = (
112
117
  ffmpeg
@@ -163,6 +168,21 @@ f
163
168
 
164
169
  See the [Usage](https://livingbio.github.io/typed-ffmpeg/usage/typed/) section in our documentation for more examples and detailed guides.
165
170
 
171
+ ---
172
+
173
+ ## Interactive Playground
174
+
175
+ Try out `typed-ffmpeg` directly in your browser with our [Interactive Playground](https://livingbio.github.io/typed-ffmpeg-playground/)! The playground provides a live environment where you can:
176
+
177
+ ![Interactive Playground](https://raw.githubusercontent.com/livingbio/typed-ffmpeg/main/docs/media/playground-screenshot.png)
178
+
179
+ - Experiment with FFmpeg filters and commands
180
+ - Visualize filter graphs in real-time
181
+ - Test different input/output configurations
182
+ - Learn through interactive examples
183
+ - Share your filter graphs with others
184
+
185
+ The playground is perfect for learning and prototyping FFmpeg filter chains without setting up a local environment.
166
186
 
167
187
  ---
168
188
 
@@ -179,4 +199,3 @@ This project is dedicated to my son, Austin, on his seventh birthday (February 2
179
199
  ---
180
200
 
181
201
  Feel free to check the [Documentation](https://livingbio.github.io/typed-ffmpeg/) for detailed information and more advanced features.
182
-
@@ -0,0 +1,58 @@
1
+ typed_ffmpeg/__init__.py,sha256=n1SZfENc9xhZ0eA3ZzkBNPuIY-Pt3-rOwB8-uUj5olU,1592
2
+ typed_ffmpeg/_version.py,sha256=VfQFwh2Vyb8ry8WT1y6VfXFKIN0E2GC1aed16irkCFQ,511
3
+ typed_ffmpeg/base.py,sha256=C5Tqbx2I0c-09D7aXKZoGkspu-lAAeAhuOns5zr3PXQ,6304
4
+ typed_ffmpeg/exceptions.py,sha256=D4SID6WOwkjVV8O8mAjrEDHWn-8BRDnK_jteaDof1SY,2474
5
+ typed_ffmpeg/filters.py,sha256=_lBpGZgPHK3KgGVrw-TCdQEsBRuEXVIgwggYNGd80MU,110076
6
+ typed_ffmpeg/info.py,sha256=0KCzf8hJaI6ObPRT0uftLa96RlYvaQmoEq1sqFJSc24,9521
7
+ typed_ffmpeg/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ typed_ffmpeg/schema.py,sha256=KVtmyGeJutjFot70r6Nj8W8WBqwvfg2-rSgjdhPVh-o,1615
9
+ typed_ffmpeg/sources.py,sha256=ASt0l8FMW82X-70qw72167xpyBY7tQQClVuhy8r0HfU,86026
10
+ typed_ffmpeg/types.py,sha256=ly3zLtg7KxRa_jsDDrFPAxRZRjTQdWVpiQzOD9NdrFM,4137
11
+ typed_ffmpeg/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ typed_ffmpeg/common/cache.py,sha256=j0JvfX7jewLpdJWxgo7Pwze0BkUJdYGHX2uGR8BZ-9M,1386
13
+ typed_ffmpeg/common/schema.py,sha256=qM8yfMX9UU3EAQSNsTrr-SAmyqKx8eQCXTtu3RJWkEk,19673
14
+ typed_ffmpeg/common/serialize.py,sha256=dLim0DBP5CdJ1JiMV9xEmmh1XMSIhBOWs61EopAL15s,7719
15
+ typed_ffmpeg/compile/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
+ typed_ffmpeg/compile/compile_cli.py,sha256=nLrTV5nuC1ETff8C7_ZgZDKPtvXJoQfZsAbm_oq1WA8,28397
17
+ typed_ffmpeg/compile/compile_json.py,sha256=YCiTyfAnUVSbFr7BiQpmJYs13K5sa-xo77Iih33mb6I,992
18
+ typed_ffmpeg/compile/compile_python.py,sha256=oo4e8Ldwk0OkrZtHucfuGR5JDFF8xY8omNKPMDyUpQ8,11506
19
+ typed_ffmpeg/compile/context.py,sha256=macQ3HhEJ73j_WbWYtU9GCQCzcB_KQGAPimcuU-WOac,10946
20
+ typed_ffmpeg/compile/validate.py,sha256=QsWksdvlRwWw6hnatFo-ABakms1qDXRbEmvMQGRLrD8,9579
21
+ typed_ffmpeg/dag/__init__.py,sha256=qAApSNqjbZ1DtUaV5bSku9RwG7MpMPa1HJO764cSBt4,849
22
+ typed_ffmpeg/dag/factory.py,sha256=2IMVKP_2UaTrlGXBg8YDx5KXBqhpScJiJQ87PRrppzY,3147
23
+ typed_ffmpeg/dag/nodes.py,sha256=lfHChT8JqRs3UUDWtgrWnnXn845HXSD5S1QmHpIUT4U,20526
24
+ typed_ffmpeg/dag/schema.py,sha256=dSq0o8e9qFazyd55k2yXcxbjoKZJEtqeROd91w1O3Wo,5728
25
+ typed_ffmpeg/dag/utils.py,sha256=hydh7_kjpOCw8WEGhXMxIXR4Ek-3DeoOt6esInuK2Xw,1941
26
+ typed_ffmpeg/dag/global_runnable/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
+ typed_ffmpeg/dag/global_runnable/global_args.py,sha256=ehLtx4v-XxqkmODhpE_gik0r79hs4Sa8TJnRsH9Fj1o,8043
28
+ typed_ffmpeg/dag/global_runnable/runnable.py,sha256=0QGBm3ghM4LFT4H9km9-h_N0w5BR3kTaESRapb-qTv0,11098
29
+ typed_ffmpeg/dag/io/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
+ typed_ffmpeg/dag/io/_input.py,sha256=KRLTSQPEfmgPcPEAJdeWRHZhNsClaJCB9Ac6czMOrmE,7214
31
+ typed_ffmpeg/dag/io/_output.py,sha256=_no6ffAOABznbLNTki8CYr7pvr4Sa0LweRfn38-cszs,12470
32
+ typed_ffmpeg/dag/io/output_args.py,sha256=SThIhZh9PXs2m6Fz5JsSy8oS-Te7GM_oz7HRuZo0-eI,13901
33
+ typed_ffmpeg/ffprobe/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
34
+ typed_ffmpeg/ffprobe/parse.py,sha256=fq1cGFkUpUdvyVi3S-TAQ7qn-tXUdae6ADhymZt7-t4,3791
35
+ typed_ffmpeg/ffprobe/probe.py,sha256=D_opsKp3OgT2HSBzhxgY1b9SIqXpDhz3xh_k9HUGux0,10367
36
+ typed_ffmpeg/ffprobe/schema.py,sha256=PBgBWYGO8wKnI0Lae9oCJ1Nprhv2ciPkdLrumzPVllY,13631
37
+ typed_ffmpeg/ffprobe/xml2json.py,sha256=1TSuxR7SYc-M_-JmE-1khHGbXCapgW0Oap9kzL0nwNg,2455
38
+ typed_ffmpeg/streams/__init__.py,sha256=Nt9uWpcVI1sQLl5Qt_kBCBcWOGZA1vczCQ0qvFbSko0,141
39
+ typed_ffmpeg/streams/audio.py,sha256=2oNRhb5UetWtlPG3NW73AjUZoFPl303yMv-6W1sGWt0,259054
40
+ typed_ffmpeg/streams/av.py,sha256=Nu6M7uV4aMNQf_kxADZuBdpDwFx_B7Z7x0p5j32n9iA,1500
41
+ typed_ffmpeg/streams/channel_layout.py,sha256=hGagaoc1tnWS8K1yiITp4f_92qq5e7C_zB15bHOL0DI,1162
42
+ typed_ffmpeg/streams/video.py,sha256=cQwHfew75YO_dbZjmpUYd-nXt1JHN0M7suFKKe5UH5s,453576
43
+ typed_ffmpeg/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
44
+ typed_ffmpeg/utils/escaping.py,sha256=m6CTEBwWZTFdtZHTHW-3pQCgkpdZb9f9ynoO-gsD7uM,2937
45
+ typed_ffmpeg/utils/forzendict.py,sha256=9QWdPQA2AbSfiC9-mrq1YeZFl1qN--zw8WlsqQ2ulCk,3114
46
+ typed_ffmpeg/utils/run.py,sha256=mSoAdcvD-InldqkRgWNc8iXKgJJoEMAOE4PL2gVmtqw,2178
47
+ typed_ffmpeg/utils/snapshot.py,sha256=mKILRm6qiQV2egaD-70MSUEl-DFoLD5w_v9GZIequI4,2181
48
+ typed_ffmpeg/utils/typing.py,sha256=DBQn_gCF8C_DTwsfMHeCgfnNUROwAjlIcHrQ7lNDOoE,1187
49
+ typed_ffmpeg/utils/view.py,sha256=QCSlQoQkRBI-T0sWjiywGgM9DlKd8Te3CB2ZYX-pEVU,3413
50
+ typed_ffmpeg/utils/lazy_eval/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
51
+ typed_ffmpeg/utils/lazy_eval/operator.py,sha256=QWybd-UH3VdDa8kgWkqAMi3WV0b0WF1d1JixQr6is2E,4136
52
+ typed_ffmpeg/utils/lazy_eval/schema.py,sha256=WSg-E3MS3itN1AT6Dq4Z9btnRHEReuN3o6zruXou7h4,9623
53
+ typed_ffmpeg_compatible-3.2.2.dist-info/licenses/LICENSE,sha256=8Aaya5i_09Cou2i3QMxTwz6uHGzi_fGA4uhkco07-A4,1066
54
+ typed_ffmpeg_compatible-3.2.2.dist-info/METADATA,sha256=eJv1JAMT41NxhuCYDvTZOBNyU5n2XoiFfyDTVtohI28,8385
55
+ typed_ffmpeg_compatible-3.2.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
56
+ typed_ffmpeg_compatible-3.2.2.dist-info/entry_points.txt,sha256=kUQvZ27paV-07qtkIFV-emKsYtjFOTw9kknBRSXPs04,45
57
+ typed_ffmpeg_compatible-3.2.2.dist-info/top_level.txt,sha256=vuASJGVRQiNmhWY1pt0RXESWSNkknWXqWLIRAU7H_L4,13
58
+ typed_ffmpeg_compatible-3.2.2.dist-info/RECORD,,
@@ -1,4 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 1.6.1
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
+