typed-ffmpeg-compatible 3.2.5__py3-none-any.whl → 3.3__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.
- typed_ffmpeg/_version.py +2 -2
- typed_ffmpeg/compile/compile_cli.py +15 -4
- typed_ffmpeg/compile/compile_python.py +3 -12
- typed_ffmpeg/dag/schema.py +8 -0
- typed_ffmpeg/streams/av.py +15 -6
- {typed_ffmpeg_compatible-3.2.5.dist-info → typed_ffmpeg_compatible-3.3.dist-info}/METADATA +1 -1
- {typed_ffmpeg_compatible-3.2.5.dist-info → typed_ffmpeg_compatible-3.3.dist-info}/RECORD +11 -11
- {typed_ffmpeg_compatible-3.2.5.dist-info → typed_ffmpeg_compatible-3.3.dist-info}/WHEEL +0 -0
- {typed_ffmpeg_compatible-3.2.5.dist-info → typed_ffmpeg_compatible-3.3.dist-info}/entry_points.txt +0 -0
- {typed_ffmpeg_compatible-3.2.5.dist-info → typed_ffmpeg_compatible-3.3.dist-info}/licenses/LICENSE +0 -0
- {typed_ffmpeg_compatible-3.2.5.dist-info → typed_ffmpeg_compatible-3.3.dist-info}/top_level.txt +0 -0
typed_ffmpeg/_version.py
CHANGED
@@ -20,6 +20,7 @@ import re
|
|
20
20
|
import shlex
|
21
21
|
from collections import defaultdict
|
22
22
|
from collections.abc import Mapping
|
23
|
+
from dataclasses import replace
|
23
24
|
|
24
25
|
from ..base import input, merge_outputs, output
|
25
26
|
from ..common.cache import load
|
@@ -141,6 +142,12 @@ def parse_stream_selector(
|
|
141
142
|
stream = mapping[stream_label]
|
142
143
|
|
143
144
|
if isinstance(stream, AVStream):
|
145
|
+
if "?" in selector:
|
146
|
+
optional = True
|
147
|
+
selector = selector.strip("?")
|
148
|
+
else:
|
149
|
+
optional = False
|
150
|
+
|
144
151
|
if ":" in selector:
|
145
152
|
if selector.count(":") == 1:
|
146
153
|
stream_label, stream_type = selector.split(":", 1)
|
@@ -151,13 +158,14 @@ def parse_stream_selector(
|
|
151
158
|
|
152
159
|
match stream_type:
|
153
160
|
case "v":
|
154
|
-
return stream.video_stream(stream_index)
|
161
|
+
return stream.video_stream(stream_index, optional)
|
155
162
|
case "a":
|
156
|
-
return stream.audio_stream(stream_index)
|
163
|
+
return stream.audio_stream(stream_index, optional)
|
157
164
|
case "s":
|
158
|
-
return stream.subtitle_stream(stream_index)
|
165
|
+
return stream.subtitle_stream(stream_index, optional)
|
159
166
|
case _:
|
160
167
|
raise FFMpegValueError(f"Unknown stream type: {stream_type}")
|
168
|
+
return replace(stream, optional=optional)
|
161
169
|
return stream
|
162
170
|
|
163
171
|
|
@@ -812,7 +820,10 @@ def get_args_output_node(node: OutputNode, context: DAGContext) -> list[str]:
|
|
812
820
|
and len(node.inputs) == 1
|
813
821
|
):
|
814
822
|
continue
|
815
|
-
|
823
|
+
if not input.optional:
|
824
|
+
commands += ["-map", get_stream_label(input, context)]
|
825
|
+
else:
|
826
|
+
commands += ["-map", f"{get_stream_label(input, context)}?"]
|
816
827
|
else:
|
817
828
|
commands += ["-map", f"[{get_stream_label(input, context)}]"]
|
818
829
|
|
@@ -77,10 +77,7 @@ def get_input_var_name(
|
|
77
77
|
case VideoStream():
|
78
78
|
match stream.node:
|
79
79
|
case InputNode():
|
80
|
-
|
81
|
-
return f"{get_output_var_name(stream.node, context)}.video_stream({stream.index})"
|
82
|
-
else:
|
83
|
-
return f"{get_output_var_name(stream.node, context)}.video"
|
80
|
+
return f"{get_output_var_name(stream.node, context)}.video_stream({stream.index}, optional={stream.optional})"
|
84
81
|
case FilterNode():
|
85
82
|
if filter_data_dict[stream.node.name].is_dynamic_output:
|
86
83
|
return f"{get_output_var_name(stream.node, context)}.video({filter_stream_typed_index(stream, context)})"
|
@@ -94,10 +91,7 @@ def get_input_var_name(
|
|
94
91
|
case AudioStream():
|
95
92
|
match stream.node:
|
96
93
|
case InputNode():
|
97
|
-
|
98
|
-
return f"{get_output_var_name(stream.node, context)}.audio_stream({stream.index})"
|
99
|
-
else:
|
100
|
-
return f"{get_output_var_name(stream.node, context)}.audio"
|
94
|
+
return f"{get_output_var_name(stream.node, context)}.audio_stream({stream.index}, optional={stream.optional})"
|
101
95
|
case FilterNode():
|
102
96
|
if filter_data_dict[stream.node.name].is_dynamic_output:
|
103
97
|
return f"{get_output_var_name(stream.node, context)}.audio({filter_stream_typed_index(stream, context)})"
|
@@ -111,10 +105,7 @@ def get_input_var_name(
|
|
111
105
|
case SubtitleStream():
|
112
106
|
match stream.node:
|
113
107
|
case InputNode():
|
114
|
-
|
115
|
-
return f"{get_output_var_name(stream.node, context)}.subtitle_stream({stream.index})"
|
116
|
-
else:
|
117
|
-
return f"{get_output_var_name(stream.node, context)}.subtitle"
|
108
|
+
return f"{get_output_var_name(stream.node, context)}.subtitle_stream({stream.index}, optional={stream.optional})"
|
118
109
|
case OutputStream():
|
119
110
|
return f"{get_output_var_name(stream.node, context)}"
|
120
111
|
case GlobalStream():
|
typed_ffmpeg/dag/schema.py
CHANGED
@@ -49,6 +49,14 @@ class Stream(HashableBaseModel):
|
|
49
49
|
See Also: [Stream specifiers](https://ffmpeg.org/ffmpeg.html#Stream-specifiers-1) `stream_index`
|
50
50
|
"""
|
51
51
|
|
52
|
+
optional: bool = False
|
53
|
+
"""
|
54
|
+
Represents whether the stream is optional.
|
55
|
+
|
56
|
+
Note:
|
57
|
+
See Also: [Advanced options](https://ffmpeg.org/ffmpeg.html#Advanced-options)
|
58
|
+
"""
|
59
|
+
|
52
60
|
def view(self, format: Literal["png", "svg", "dot"] = "png") -> str:
|
53
61
|
"""
|
54
62
|
Visualize the stream.
|
typed_ffmpeg/streams/av.py
CHANGED
@@ -41,38 +41,47 @@ class AVStream(AudioStream, VideoStream):
|
|
41
41
|
"""
|
42
42
|
return SubtitleStream(node=self.node, index=self.index)
|
43
43
|
|
44
|
-
def video_stream(
|
44
|
+
def video_stream(
|
45
|
+
self, index: int | None = None, optional: bool = False
|
46
|
+
) -> VideoStream:
|
45
47
|
"""
|
46
48
|
Get the video stream from the input node with a specified index.
|
47
49
|
|
48
50
|
Args:
|
49
51
|
index: The index of the video stream.
|
52
|
+
optional: Whether the video stream is optional.
|
50
53
|
|
51
54
|
Returns:
|
52
55
|
VideoStream: The video stream from the input node.
|
53
56
|
"""
|
54
|
-
return VideoStream(node=self.node, index=index)
|
57
|
+
return VideoStream(node=self.node, index=index, optional=optional)
|
55
58
|
|
56
|
-
def audio_stream(
|
59
|
+
def audio_stream(
|
60
|
+
self, index: int | None = None, optional: bool = False
|
61
|
+
) -> AudioStream:
|
57
62
|
"""
|
58
63
|
Get the audio stream from the input node with a specified index.
|
59
64
|
|
60
65
|
Args:
|
61
66
|
index: The index of the audio stream.
|
67
|
+
optional: Whether the audio stream is optional.
|
62
68
|
|
63
69
|
Returns:
|
64
70
|
AudioStream: The audio stream from the input node.
|
65
71
|
"""
|
66
|
-
return AudioStream(node=self.node, index=index)
|
72
|
+
return AudioStream(node=self.node, index=index, optional=optional)
|
67
73
|
|
68
|
-
def subtitle_stream(
|
74
|
+
def subtitle_stream(
|
75
|
+
self, index: int | None = None, optional: bool = False
|
76
|
+
) -> SubtitleStream:
|
69
77
|
"""
|
70
78
|
Get the subtitle stream from the input node with a specified index.
|
71
79
|
|
72
80
|
Args:
|
73
81
|
index: The index of the subtitle stream.
|
82
|
+
optional: Whether the subtitle stream is optional.
|
74
83
|
|
75
84
|
Returns:
|
76
85
|
SubtitleStream: The subtitle stream from the input node.
|
77
86
|
"""
|
78
|
-
return SubtitleStream(node=self.node, index=index)
|
87
|
+
return SubtitleStream(node=self.node, index=index, optional=optional)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: typed-ffmpeg-compatible
|
3
|
-
Version: 3.
|
3
|
+
Version: 3.3
|
4
4
|
Summary: Modern Python FFmpeg wrappers offer comprehensive support for complex filters, complete with detailed typing and documentation.
|
5
5
|
Author-email: lucemia <lucemia@gmail.com>
|
6
6
|
License-Expression: MIT
|
@@ -1,5 +1,5 @@
|
|
1
1
|
typed_ffmpeg/__init__.py,sha256=n1SZfENc9xhZ0eA3ZzkBNPuIY-Pt3-rOwB8-uUj5olU,1592
|
2
|
-
typed_ffmpeg/_version.py,sha256=
|
2
|
+
typed_ffmpeg/_version.py,sha256=lgTPmPhRGLqWrHHDFV9z5QiSuA5Dn5Dch5YbYnpAWj4,506
|
3
3
|
typed_ffmpeg/base.py,sha256=C5Tqbx2I0c-09D7aXKZoGkspu-lAAeAhuOns5zr3PXQ,6304
|
4
4
|
typed_ffmpeg/exceptions.py,sha256=D4SID6WOwkjVV8O8mAjrEDHWn-8BRDnK_jteaDof1SY,2474
|
5
5
|
typed_ffmpeg/filters.py,sha256=_lBpGZgPHK3KgGVrw-TCdQEsBRuEXVIgwggYNGd80MU,110076
|
@@ -13,15 +13,15 @@ typed_ffmpeg/common/cache.py,sha256=j0JvfX7jewLpdJWxgo7Pwze0BkUJdYGHX2uGR8BZ-9M,
|
|
13
13
|
typed_ffmpeg/common/schema.py,sha256=qM8yfMX9UU3EAQSNsTrr-SAmyqKx8eQCXTtu3RJWkEk,19673
|
14
14
|
typed_ffmpeg/common/serialize.py,sha256=dLim0DBP5CdJ1JiMV9xEmmh1XMSIhBOWs61EopAL15s,7719
|
15
15
|
typed_ffmpeg/compile/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
16
|
-
typed_ffmpeg/compile/compile_cli.py,sha256=
|
16
|
+
typed_ffmpeg/compile/compile_cli.py,sha256=Xuz4gAp4kqeywOxBNgPXH_Ie8lrmwfEdAl-HxMGo9kI,32892
|
17
17
|
typed_ffmpeg/compile/compile_json.py,sha256=YCiTyfAnUVSbFr7BiQpmJYs13K5sa-xo77Iih33mb6I,992
|
18
|
-
typed_ffmpeg/compile/compile_python.py,sha256=
|
18
|
+
typed_ffmpeg/compile/compile_python.py,sha256=YnnRRHE8TEUiqFF9DsqkYOwIcA2ejCYw12k-O5n825A,11506
|
19
19
|
typed_ffmpeg/compile/context.py,sha256=macQ3HhEJ73j_WbWYtU9GCQCzcB_KQGAPimcuU-WOac,10946
|
20
20
|
typed_ffmpeg/compile/validate.py,sha256=QsWksdvlRwWw6hnatFo-ABakms1qDXRbEmvMQGRLrD8,9579
|
21
21
|
typed_ffmpeg/dag/__init__.py,sha256=qAApSNqjbZ1DtUaV5bSku9RwG7MpMPa1HJO764cSBt4,849
|
22
22
|
typed_ffmpeg/dag/factory.py,sha256=2IMVKP_2UaTrlGXBg8YDx5KXBqhpScJiJQ87PRrppzY,3147
|
23
23
|
typed_ffmpeg/dag/nodes.py,sha256=lfHChT8JqRs3UUDWtgrWnnXn845HXSD5S1QmHpIUT4U,20526
|
24
|
-
typed_ffmpeg/dag/schema.py,sha256=
|
24
|
+
typed_ffmpeg/dag/schema.py,sha256=xsVT46XgT3Usgb4N9OWdjP74MG9dBrXgZGbjsYhsUEM,5916
|
25
25
|
typed_ffmpeg/dag/utils.py,sha256=hydh7_kjpOCw8WEGhXMxIXR4Ek-3DeoOt6esInuK2Xw,1941
|
26
26
|
typed_ffmpeg/dag/global_runnable/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
27
27
|
typed_ffmpeg/dag/global_runnable/global_args.py,sha256=ehLtx4v-XxqkmODhpE_gik0r79hs4Sa8TJnRsH9Fj1o,8043
|
@@ -37,7 +37,7 @@ typed_ffmpeg/ffprobe/schema.py,sha256=PBgBWYGO8wKnI0Lae9oCJ1Nprhv2ciPkdLrumzPVll
|
|
37
37
|
typed_ffmpeg/ffprobe/xml2json.py,sha256=1TSuxR7SYc-M_-JmE-1khHGbXCapgW0Oap9kzL0nwNg,2455
|
38
38
|
typed_ffmpeg/streams/__init__.py,sha256=Nt9uWpcVI1sQLl5Qt_kBCBcWOGZA1vczCQ0qvFbSko0,141
|
39
39
|
typed_ffmpeg/streams/audio.py,sha256=2oNRhb5UetWtlPG3NW73AjUZoFPl303yMv-6W1sGWt0,259054
|
40
|
-
typed_ffmpeg/streams/av.py,sha256=
|
40
|
+
typed_ffmpeg/streams/av.py,sha256=qrsO692BG6OVMWVwIeuCKPntBGTR685lc2ULbGPTSkQ,2594
|
41
41
|
typed_ffmpeg/streams/channel_layout.py,sha256=hGagaoc1tnWS8K1yiITp4f_92qq5e7C_zB15bHOL0DI,1162
|
42
42
|
typed_ffmpeg/streams/subtitle.py,sha256=zhbRKUYH0C972Hurm4hK_dqLvT4Y6v_VNZFzQrkCm9A,141
|
43
43
|
typed_ffmpeg/streams/video.py,sha256=cQwHfew75YO_dbZjmpUYd-nXt1JHN0M7suFKKe5UH5s,453576
|
@@ -51,9 +51,9 @@ typed_ffmpeg/utils/view.py,sha256=QCSlQoQkRBI-T0sWjiywGgM9DlKd8Te3CB2ZYX-pEVU,34
|
|
51
51
|
typed_ffmpeg/utils/lazy_eval/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
52
52
|
typed_ffmpeg/utils/lazy_eval/operator.py,sha256=QWybd-UH3VdDa8kgWkqAMi3WV0b0WF1d1JixQr6is2E,4136
|
53
53
|
typed_ffmpeg/utils/lazy_eval/schema.py,sha256=WSg-E3MS3itN1AT6Dq4Z9btnRHEReuN3o6zruXou7h4,9623
|
54
|
-
typed_ffmpeg_compatible-3.
|
55
|
-
typed_ffmpeg_compatible-3.
|
56
|
-
typed_ffmpeg_compatible-3.
|
57
|
-
typed_ffmpeg_compatible-3.
|
58
|
-
typed_ffmpeg_compatible-3.
|
59
|
-
typed_ffmpeg_compatible-3.
|
54
|
+
typed_ffmpeg_compatible-3.3.dist-info/licenses/LICENSE,sha256=8Aaya5i_09Cou2i3QMxTwz6uHGzi_fGA4uhkco07-A4,1066
|
55
|
+
typed_ffmpeg_compatible-3.3.dist-info/METADATA,sha256=FtrDI-yit60_yKnw5CfgYotZX9MLBIMiNtqCXBnDPmA,8383
|
56
|
+
typed_ffmpeg_compatible-3.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
57
|
+
typed_ffmpeg_compatible-3.3.dist-info/entry_points.txt,sha256=kUQvZ27paV-07qtkIFV-emKsYtjFOTw9kknBRSXPs04,45
|
58
|
+
typed_ffmpeg_compatible-3.3.dist-info/top_level.txt,sha256=vuASJGVRQiNmhWY1pt0RXESWSNkknWXqWLIRAU7H_L4,13
|
59
|
+
typed_ffmpeg_compatible-3.3.dist-info/RECORD,,
|
File without changes
|
{typed_ffmpeg_compatible-3.2.5.dist-info → typed_ffmpeg_compatible-3.3.dist-info}/entry_points.txt
RENAMED
File without changes
|
{typed_ffmpeg_compatible-3.2.5.dist-info → typed_ffmpeg_compatible-3.3.dist-info}/licenses/LICENSE
RENAMED
File without changes
|
{typed_ffmpeg_compatible-3.2.5.dist-info → typed_ffmpeg_compatible-3.3.dist-info}/top_level.txt
RENAMED
File without changes
|