auto-editor 26.3.2__py3-none-any.whl → 27.0.0__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.
- auto_editor/__init__.py +1 -1
- auto_editor/__main__.py +155 -40
- auto_editor/analyze.py +30 -36
- auto_editor/cmds/info.py +1 -1
- auto_editor/cmds/levels.py +3 -3
- auto_editor/cmds/subdump.py +62 -8
- auto_editor/cmds/test.py +73 -53
- auto_editor/edit.py +50 -58
- auto_editor/ffwrapper.py +9 -9
- auto_editor/formats/json.py +2 -2
- auto_editor/{lang/json.py → json.py} +39 -43
- auto_editor/lang/palet.py +2 -2
- auto_editor/lang/stdenv.py +12 -0
- auto_editor/make_layers.py +2 -1
- auto_editor/output.py +6 -6
- auto_editor/render/audio.py +30 -25
- auto_editor/render/subtitle.py +10 -14
- auto_editor/render/video.py +41 -45
- auto_editor/timeline.py +8 -1
- auto_editor/utils/container.py +3 -3
- auto_editor/utils/types.py +7 -118
- {auto_editor-26.3.2.dist-info → auto_editor-27.0.0.dist-info}/METADATA +8 -7
- {auto_editor-26.3.2.dist-info → auto_editor-27.0.0.dist-info}/RECORD +28 -28
- {auto_editor-26.3.2.dist-info → auto_editor-27.0.0.dist-info}/WHEEL +1 -1
- docs/build.py +16 -7
- {auto_editor-26.3.2.dist-info → auto_editor-27.0.0.dist-info}/entry_points.txt +0 -0
- {auto_editor-26.3.2.dist-info → auto_editor-27.0.0.dist-info/licenses}/LICENSE +0 -0
- {auto_editor-26.3.2.dist-info → auto_editor-27.0.0.dist-info}/top_level.txt +0 -0
auto_editor/render/video.py
CHANGED
@@ -3,7 +3,7 @@ from __future__ import annotations
|
|
3
3
|
from dataclasses import dataclass
|
4
4
|
from typing import TYPE_CHECKING
|
5
5
|
|
6
|
-
import
|
6
|
+
import bv
|
7
7
|
import numpy as np
|
8
8
|
|
9
9
|
from auto_editor.output import parse_bitrate
|
@@ -11,12 +11,11 @@ from auto_editor.timeline import TlImage, TlRect, TlVideo
|
|
11
11
|
|
12
12
|
if TYPE_CHECKING:
|
13
13
|
from collections.abc import Iterator
|
14
|
-
from typing import Any
|
15
14
|
|
15
|
+
from auto_editor.__main__ import Args
|
16
16
|
from auto_editor.ffwrapper import FileInfo
|
17
17
|
from auto_editor.timeline import v3
|
18
18
|
from auto_editor.utils.log import Log
|
19
|
-
from auto_editor.utils.types import Args
|
20
19
|
|
21
20
|
|
22
21
|
@dataclass(slots=True)
|
@@ -25,15 +24,12 @@ class VideoFrame:
|
|
25
24
|
src: FileInfo
|
26
25
|
|
27
26
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
def make_solid(width: int, height: int, pix_fmt: str, bg: str) -> av.VideoFrame:
|
27
|
+
def make_solid(width: int, height: int, pix_fmt: str, bg: str) -> bv.VideoFrame:
|
32
28
|
hex_color = bg.lstrip("#").upper()
|
33
29
|
rgb_color = tuple(int(hex_color[i : i + 2], 16) for i in (0, 2, 4))
|
34
30
|
|
35
31
|
rgb_array = np.full((height, width, 3), rgb_color, dtype=np.uint8)
|
36
|
-
rgb_frame =
|
32
|
+
rgb_frame = bv.VideoFrame.from_ndarray(rgb_array, format="rgb24")
|
37
33
|
return rgb_frame.reformat(format=pix_fmt)
|
38
34
|
|
39
35
|
|
@@ -42,11 +38,11 @@ def make_image_cache(tl: v3) -> dict[tuple[FileInfo, int], np.ndarray]:
|
|
42
38
|
for clip in tl.v:
|
43
39
|
for obj in clip:
|
44
40
|
if isinstance(obj, TlImage) and (obj.src, obj.width) not in img_cache:
|
45
|
-
with
|
41
|
+
with bv.open(obj.src.path) as cn:
|
46
42
|
my_stream = cn.streams.video[0]
|
47
43
|
for frame in cn.decode(my_stream):
|
48
44
|
if obj.width != 0:
|
49
|
-
graph =
|
45
|
+
graph = bv.filter.Graph()
|
50
46
|
graph.link_nodes(
|
51
47
|
graph.add_buffer(template=my_stream),
|
52
48
|
graph.add("scale", f"{obj.width}:-1"),
|
@@ -61,17 +57,17 @@ def make_image_cache(tl: v3) -> dict[tuple[FileInfo, int], np.ndarray]:
|
|
61
57
|
|
62
58
|
|
63
59
|
def render_av(
|
64
|
-
output:
|
65
|
-
) ->
|
66
|
-
from_ndarray =
|
60
|
+
output: bv.container.OutputContainer, tl: v3, args: Args, log: Log
|
61
|
+
) -> Iterator[tuple[int, bv.VideoFrame]]:
|
62
|
+
from_ndarray = bv.VideoFrame.from_ndarray
|
67
63
|
|
68
64
|
src = tl.src
|
69
|
-
cns: dict[FileInfo,
|
70
|
-
decoders: dict[FileInfo, Iterator[
|
65
|
+
cns: dict[FileInfo, bv.container.InputContainer] = {}
|
66
|
+
decoders: dict[FileInfo, Iterator[bv.VideoFrame]] = {}
|
71
67
|
seek_cost: dict[FileInfo, int] = {}
|
72
68
|
tous: dict[FileInfo, int] = {}
|
73
69
|
|
74
|
-
|
70
|
+
pix_fmt = "yuv420p" # Reasonable default
|
75
71
|
target_fps = tl.tb # Always constant
|
76
72
|
img_cache = make_image_cache(tl)
|
77
73
|
|
@@ -81,7 +77,7 @@ def render_av(
|
|
81
77
|
first_src = src
|
82
78
|
|
83
79
|
if src not in cns:
|
84
|
-
cns[src] =
|
80
|
+
cns[src] = bv.open(f"{src.path}")
|
85
81
|
|
86
82
|
for src, cn in cns.items():
|
87
83
|
if len(cn.streams.video) > 0:
|
@@ -101,30 +97,30 @@ def render_av(
|
|
101
97
|
decoders[src] = cn.decode(stream)
|
102
98
|
|
103
99
|
if src == first_src and stream.pix_fmt is not None:
|
104
|
-
|
100
|
+
pix_fmt = stream.pix_fmt
|
105
101
|
|
106
102
|
log.debug(f"Tous: {tous}")
|
107
103
|
log.debug(f"Clips: {tl.v}")
|
108
104
|
|
109
|
-
codec =
|
105
|
+
codec = bv.Codec(args.video_codec, "w")
|
106
|
+
|
107
|
+
need_valid_fmt = True
|
108
|
+
if codec.video_formats is not None:
|
109
|
+
for video_format in codec.video_formats:
|
110
|
+
if pix_fmt == video_format.name:
|
111
|
+
need_valid_fmt = False
|
112
|
+
break
|
110
113
|
|
111
|
-
if
|
112
|
-
if codec.
|
113
|
-
|
114
|
-
|
115
|
-
|
114
|
+
if need_valid_fmt:
|
115
|
+
if codec.canonical_name == "gif":
|
116
|
+
pix_fmt = "rgb8"
|
117
|
+
elif codec.canonical_name == "prores":
|
118
|
+
pix_fmt = "yuv422p10le"
|
116
119
|
else:
|
117
|
-
|
118
|
-
elif codec.canonical_name == "prores":
|
119
|
-
target_pix_fmt = "yuv422p10le"
|
120
|
-
else:
|
121
|
-
target_pix_fmt = (
|
122
|
-
target_pix_fmt if target_pix_fmt in allowed_pix_fmt else "yuv420p"
|
123
|
-
)
|
120
|
+
pix_fmt = "yuv420p"
|
124
121
|
|
125
122
|
del codec
|
126
|
-
|
127
|
-
output_stream = output.add_stream(args.video_codec, rate=target_fps, options=ops)
|
123
|
+
output_stream = output.add_stream(args.video_codec, rate=target_fps)
|
128
124
|
|
129
125
|
cc = output_stream.codec_context
|
130
126
|
if args.vprofile is not None:
|
@@ -136,8 +132,8 @@ def render_av(
|
|
136
132
|
|
137
133
|
cc.profile = args.vprofile.title()
|
138
134
|
|
139
|
-
yield output_stream
|
140
|
-
if not isinstance(output_stream,
|
135
|
+
yield output_stream # type: ignore
|
136
|
+
if not isinstance(output_stream, bv.VideoStream):
|
141
137
|
log.error(f"Not a known video codec: {args.video_codec}")
|
142
138
|
if src.videos and src.videos[0].lang is not None:
|
143
139
|
output_stream.metadata["language"] = src.videos[0].lang
|
@@ -148,10 +144,10 @@ def render_av(
|
|
148
144
|
else:
|
149
145
|
target_width = max(round(tl.res[0] * args.scale), 2)
|
150
146
|
target_height = max(round(tl.res[1] * args.scale), 2)
|
151
|
-
scale_graph =
|
147
|
+
scale_graph = bv.filter.Graph()
|
152
148
|
scale_graph.link_nodes(
|
153
149
|
scale_graph.add(
|
154
|
-
"buffer", video_size="1x1", time_base="1/1", pix_fmt=
|
150
|
+
"buffer", video_size="1x1", time_base="1/1", pix_fmt=pix_fmt
|
155
151
|
),
|
156
152
|
scale_graph.add("scale", f"{target_width}:{target_height}"),
|
157
153
|
scale_graph.add("buffersink"),
|
@@ -159,7 +155,7 @@ def render_av(
|
|
159
155
|
|
160
156
|
output_stream.width = target_width
|
161
157
|
output_stream.height = target_height
|
162
|
-
output_stream.pix_fmt =
|
158
|
+
output_stream.pix_fmt = pix_fmt
|
163
159
|
output_stream.framerate = target_fps
|
164
160
|
|
165
161
|
color_range = src.videos[0].color_range
|
@@ -191,7 +187,7 @@ def render_av(
|
|
191
187
|
frames_saved = 0
|
192
188
|
|
193
189
|
bg = args.background
|
194
|
-
null_frame = make_solid(target_width, target_height,
|
190
|
+
null_frame = make_solid(target_width, target_height, pix_fmt, bg)
|
195
191
|
frame_index = -1
|
196
192
|
|
197
193
|
for index in range(tl.end):
|
@@ -250,7 +246,7 @@ def render_av(
|
|
250
246
|
|
251
247
|
if (frame.width, frame.height) != tl.res:
|
252
248
|
width, height = tl.res
|
253
|
-
graph =
|
249
|
+
graph = bv.filter.Graph()
|
254
250
|
graph.link_nodes(
|
255
251
|
graph.add_buffer(template=my_stream),
|
256
252
|
graph.add(
|
@@ -262,7 +258,7 @@ def render_av(
|
|
262
258
|
).vpush(frame)
|
263
259
|
frame = graph.vpull()
|
264
260
|
elif isinstance(obj, TlRect):
|
265
|
-
graph =
|
261
|
+
graph = bv.filter.Graph()
|
266
262
|
x, y = obj.x, obj.y
|
267
263
|
graph.link_nodes(
|
268
264
|
graph.add_buffer(template=my_stream),
|
@@ -308,9 +304,9 @@ def render_av(
|
|
308
304
|
scale_graph.vpush(frame)
|
309
305
|
frame = scale_graph.vpull()
|
310
306
|
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
yield (index,
|
307
|
+
frame = frame.reformat(format=pix_fmt)
|
308
|
+
frame.pts = None # type: ignore
|
309
|
+
frame.time_base = 0 # type: ignore
|
310
|
+
yield (index, frame)
|
315
311
|
|
316
312
|
log.debug(f"Total frames saved seeking: {frames_saved}")
|
auto_editor/timeline.py
CHANGED
@@ -6,7 +6,7 @@ from typing import TYPE_CHECKING
|
|
6
6
|
from auto_editor.ffwrapper import initFileInfo, mux
|
7
7
|
from auto_editor.lib.contracts import *
|
8
8
|
from auto_editor.utils.cmdkw import Required, pAttr, pAttrs
|
9
|
-
from auto_editor.utils.types import natural, number, parse_color
|
9
|
+
from auto_editor.utils.types import CoerceError, natural, number, parse_color
|
10
10
|
|
11
11
|
if TYPE_CHECKING:
|
12
12
|
from collections.abc import Iterator
|
@@ -128,6 +128,13 @@ class TlRect:
|
|
128
128
|
}
|
129
129
|
|
130
130
|
|
131
|
+
def threshold(val: str | float) -> float:
|
132
|
+
num = number(val)
|
133
|
+
if num > 1 or num < 0:
|
134
|
+
raise CoerceError(f"'{val}': Threshold must be between 0 and 1 (0%-100%)")
|
135
|
+
return num
|
136
|
+
|
137
|
+
|
131
138
|
video_builder = pAttrs(
|
132
139
|
"video",
|
133
140
|
pAttr("start", Required, is_nat, natural),
|
auto_editor/utils/container.py
CHANGED
@@ -3,8 +3,8 @@ from __future__ import annotations
|
|
3
3
|
from dataclasses import dataclass
|
4
4
|
from typing import TypedDict
|
5
5
|
|
6
|
-
import
|
7
|
-
from
|
6
|
+
import bv
|
7
|
+
from bv.codec import Codec
|
8
8
|
|
9
9
|
|
10
10
|
class DictContainer(TypedDict, total=False):
|
@@ -61,7 +61,7 @@ def codec_type(x: str) -> str:
|
|
61
61
|
|
62
62
|
|
63
63
|
def container_constructor(ext: str) -> Container:
|
64
|
-
with
|
64
|
+
with bv.open(f".{ext}", "w") as container:
|
65
65
|
codecs = container.supported_codecs
|
66
66
|
if ext == "webm":
|
67
67
|
vdefault = "vp9"
|
auto_editor/utils/types.py
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import re
|
4
|
-
from dataclasses import dataclass, field
|
5
4
|
from fractions import Fraction
|
6
5
|
|
7
6
|
|
@@ -9,16 +8,7 @@ class CoerceError(Exception):
|
|
9
8
|
pass
|
10
9
|
|
11
10
|
|
12
|
-
def
|
13
|
-
vals = val.strip().split(",")
|
14
|
-
if num_args > len(vals):
|
15
|
-
raise CoerceError(f"Too few arguments for {name}.")
|
16
|
-
if len(vals) > num_args:
|
17
|
-
raise CoerceError(f"Too many arguments for {name}.")
|
18
|
-
return vals
|
19
|
-
|
20
|
-
|
21
|
-
def _split_num_str(val: str | float) -> tuple[float, str]:
|
11
|
+
def split_num_str(val: str | float) -> tuple[float, str]:
|
22
12
|
if isinstance(val, float | int):
|
23
13
|
return val, ""
|
24
14
|
|
@@ -35,14 +25,9 @@ def _split_num_str(val: str | float) -> tuple[float, str]:
|
|
35
25
|
return float(num), unit
|
36
26
|
|
37
27
|
|
38
|
-
def _unit_check(unit: str, allowed_units: tuple[str, ...]) -> None:
|
39
|
-
if unit not in allowed_units:
|
40
|
-
raise CoerceError(f"Unknown unit: '{unit}'")
|
41
|
-
|
42
|
-
|
43
28
|
# Numbers: 0, 1, 2, 3, ...
|
44
29
|
def natural(val: str | float) -> int:
|
45
|
-
num, unit =
|
30
|
+
num, unit = split_num_str(val)
|
46
31
|
if unit != "":
|
47
32
|
raise CoerceError(f"'{val}': Natural does not allow units.")
|
48
33
|
if not isinstance(num, int) and not num.is_integer():
|
@@ -69,25 +54,12 @@ def number(val: str | float) -> float:
|
|
69
54
|
raise CoerceError(f"'{val}': Denominator must not be zero.")
|
70
55
|
return vs[0] / vs[1]
|
71
56
|
|
72
|
-
num, unit =
|
57
|
+
num, unit = split_num_str(val)
|
73
58
|
if unit == "%":
|
74
59
|
return num / 100
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
def speed(val: str) -> float:
|
80
|
-
_s = number(val)
|
81
|
-
if _s <= 0 or _s > 99999:
|
82
|
-
return 99999.0
|
83
|
-
return _s
|
84
|
-
|
85
|
-
|
86
|
-
def threshold(val: str | float) -> float:
|
87
|
-
num = number(val)
|
88
|
-
if num > 1 or num < 0:
|
89
|
-
raise CoerceError(f"'{val}': Threshold must be between 0 and 1 (0%-100%)")
|
90
|
-
return num
|
60
|
+
if unit == "":
|
61
|
+
return num
|
62
|
+
raise CoerceError(f"Unknown unit: '{unit}'")
|
91
63
|
|
92
64
|
|
93
65
|
def frame_rate(val: str) -> Fraction:
|
@@ -102,14 +74,6 @@ def frame_rate(val: str) -> Fraction:
|
|
102
74
|
return Fraction(val)
|
103
75
|
|
104
76
|
|
105
|
-
def sample_rate(val: str) -> int:
|
106
|
-
num, unit = _split_num_str(val)
|
107
|
-
if unit in {"kHz", "KHz"}:
|
108
|
-
return natural(num * 1000)
|
109
|
-
_unit_check(unit, ("", "Hz"))
|
110
|
-
return natural(num)
|
111
|
-
|
112
|
-
|
113
77
|
def time(val: str, tb: Fraction) -> int:
|
114
78
|
if ":" in val:
|
115
79
|
boxes = val.split(":")
|
@@ -121,7 +85,7 @@ def time(val: str, tb: Fraction) -> int:
|
|
121
85
|
)
|
122
86
|
raise CoerceError(f"'{val}': Invalid time format")
|
123
87
|
|
124
|
-
num, unit =
|
88
|
+
num, unit = split_num_str(val)
|
125
89
|
if unit in {"s", "sec", "secs", "second", "seconds"}:
|
126
90
|
return round(num * tb)
|
127
91
|
if unit in {"min", "mins", "minute", "minutes"}:
|
@@ -136,25 +100,6 @@ def time(val: str, tb: Fraction) -> int:
|
|
136
100
|
return int(num)
|
137
101
|
|
138
102
|
|
139
|
-
def margin(val: str) -> tuple[str, str]:
|
140
|
-
vals = val.strip().split(",")
|
141
|
-
if len(vals) == 1:
|
142
|
-
vals.append(vals[0])
|
143
|
-
if len(vals) != 2:
|
144
|
-
raise CoerceError("--margin has too many arguments.")
|
145
|
-
return vals[0], vals[1]
|
146
|
-
|
147
|
-
|
148
|
-
def time_range(val: str) -> tuple[str, str]:
|
149
|
-
a = _comma_coerce("time_range", val, 2)
|
150
|
-
return a[0], a[1]
|
151
|
-
|
152
|
-
|
153
|
-
def speed_range(val: str) -> tuple[float, str, str]:
|
154
|
-
a = _comma_coerce("speed_range", val, 3)
|
155
|
-
return number(a[0]), a[1], a[2]
|
156
|
-
|
157
|
-
|
158
103
|
def parse_color(val: str) -> str:
|
159
104
|
"""
|
160
105
|
Convert a color str into an RGB tuple
|
@@ -179,62 +124,6 @@ def parse_color(val: str) -> str:
|
|
179
124
|
raise ValueError(f"Invalid Color: '{color}'")
|
180
125
|
|
181
126
|
|
182
|
-
def resolution(val: str | None) -> tuple[int, int] | None:
|
183
|
-
if val is None:
|
184
|
-
return None
|
185
|
-
vals = val.strip().split(",")
|
186
|
-
if len(vals) != 2:
|
187
|
-
raise CoerceError(f"'{val}': Resolution takes two numbers")
|
188
|
-
|
189
|
-
return natural(vals[0]), natural(vals[1])
|
190
|
-
|
191
|
-
|
192
|
-
@dataclass(slots=True)
|
193
|
-
class Args:
|
194
|
-
yt_dlp_location: str = "yt-dlp"
|
195
|
-
download_format: str | None = None
|
196
|
-
output_format: str | None = None
|
197
|
-
yt_dlp_extras: str | None = None
|
198
|
-
video_codec: str = "auto"
|
199
|
-
audio_codec: str = "auto"
|
200
|
-
video_bitrate: str = "auto"
|
201
|
-
vprofile: str | None = None
|
202
|
-
audio_bitrate: str = "auto"
|
203
|
-
scale: float = 1.0
|
204
|
-
fragmented: bool = False
|
205
|
-
no_fragmented: bool = False
|
206
|
-
sn: bool = False
|
207
|
-
dn: bool = False
|
208
|
-
no_seek: bool = False
|
209
|
-
cut_out: list[tuple[str, str]] = field(default_factory=list)
|
210
|
-
add_in: list[tuple[str, str]] = field(default_factory=list)
|
211
|
-
set_speed_for_range: list[tuple[float, str, str]] = field(default_factory=list)
|
212
|
-
frame_rate: Fraction | None = None
|
213
|
-
sample_rate: int | None = None
|
214
|
-
resolution: tuple[int, int] | None = None
|
215
|
-
background: str = "#000000"
|
216
|
-
edit: str = "audio"
|
217
|
-
keep_tracks_separate: bool = False
|
218
|
-
audio_normalize: str = "#f"
|
219
|
-
export: str | None = None
|
220
|
-
player: str | None = None
|
221
|
-
no_open: bool = False
|
222
|
-
temp_dir: str | None = None
|
223
|
-
progress: str = "modern"
|
224
|
-
version: bool = False
|
225
|
-
debug: bool = False
|
226
|
-
config: bool = False
|
227
|
-
quiet: bool = False
|
228
|
-
preview: bool = False
|
229
|
-
no_cache: bool = False
|
230
|
-
margin: tuple[str, str] = ("0.2s", "0.2s")
|
231
|
-
silent_speed: float = 99999.0
|
232
|
-
video_speed: float = 1.0
|
233
|
-
output_file: str | None = None
|
234
|
-
help: bool = False
|
235
|
-
input: list[str] = field(default_factory=list)
|
236
|
-
|
237
|
-
|
238
127
|
colormap = {
|
239
128
|
# Taken from https://www.w3.org/TR/css-color-4/#named-color
|
240
129
|
"aliceblue": "#f0f8ff",
|
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: auto-editor
|
3
|
-
Version:
|
3
|
+
Version: 27.0.0
|
4
4
|
Summary: Auto-Editor: Effort free video editing!
|
5
5
|
Author-email: WyattBlue <wyattblue@auto-editor.com>
|
6
6
|
License: Unlicense
|
@@ -11,8 +11,9 @@ Keywords: video,audio,media,editor,editing,processing,nonlinear,automatic,silenc
|
|
11
11
|
Requires-Python: <3.14,>=3.10
|
12
12
|
Description-Content-Type: text/markdown
|
13
13
|
License-File: LICENSE
|
14
|
-
Requires-Dist: numpy<3.0,>=
|
15
|
-
Requires-Dist:
|
14
|
+
Requires-Dist: numpy<3.0,>=2
|
15
|
+
Requires-Dist: basswood-av<16,>=15.0.0
|
16
|
+
Dynamic: license-file
|
16
17
|
|
17
18
|
<p align="center"><img src="https://auto-editor.com/img/auto-editor-banner.webp" title="Auto-Editor" width="700"></p>
|
18
19
|
|
@@ -21,7 +22,7 @@ Requires-Dist: pyav==14.2.*
|
|
21
22
|
---
|
22
23
|
|
23
24
|
[](https://github.com/wyattblue/auto-editor/actions)
|
24
|
-
|
25
|
+
[](https://github.com/astral-sh/ruff)
|
25
26
|
|
26
27
|
Before doing the real editing, you first cut out the "dead space" which is typically silence. This is known as a "first pass". Cutting these is a boring task, especially if the video is very long.
|
27
28
|
|
@@ -175,9 +176,9 @@ auto-editor --margin --help
|
|
175
176
|
|
176
177
|
## Articles
|
177
178
|
- [How to Install Auto-Editor](https://auto-editor.com/installing)
|
178
|
-
- [All the Options (And What They Do)](https://auto-editor.com/options)
|
179
|
+
- [All the Options (And What They Do)](https://auto-editor.com/ref/options)
|
179
180
|
- [Docs](https://auto-editor.com/docs)
|
180
|
-
- [Blog](https://
|
181
|
+
- [Blog](https://basswood-io.com/blog/)
|
181
182
|
|
182
183
|
## Copyright
|
183
184
|
Auto-Editor is under the [Public Domain](https://github.com/WyattBlue/auto-editor/blob/master/LICENSE) and includes all directories besides the ones listed below. Auto-Editor was created by [these people.](https://auto-editor.com/blog/thank-you-early-testers)
|
@@ -1,56 +1,56 @@
|
|
1
|
-
auto_editor/__init__.py,sha256=
|
2
|
-
auto_editor/__main__.py,sha256=
|
3
|
-
auto_editor/analyze.py,sha256=
|
4
|
-
auto_editor/edit.py,sha256=
|
5
|
-
auto_editor/ffwrapper.py,sha256=
|
1
|
+
auto_editor/__init__.py,sha256=KViW4EBA7GbEItgvzRFMRG3Xq3ASIbwCSsNE9WwakVc,23
|
2
|
+
auto_editor/__main__.py,sha256=iKfQKFOQDv0-uZecLzfb8A-0k5dAxxe94FaIIEayGXc,15575
|
3
|
+
auto_editor/analyze.py,sha256=CeJG0LI9wXZk1R-QPrNGPS4za-_Avd8y7H-D437DqLg,12300
|
4
|
+
auto_editor/edit.py,sha256=9rJC6IY-jMdQDolJBxfzng43ddYQpC8zuZQHLzEct8s,20698
|
5
|
+
auto_editor/ffwrapper.py,sha256=b2XDsJMmBnYtRAGrIjqhYH909GNo30tMW3FCZUhhZ5k,4781
|
6
6
|
auto_editor/help.py,sha256=CzfDTsL4GuGu596ySHKj_wKnxGR9h8B0KUdkZpo33oE,8044
|
7
|
-
auto_editor/
|
8
|
-
auto_editor/
|
7
|
+
auto_editor/json.py,sha256=8IVhZJSLx2IVqJsbR5YKDvbHOhgIOvdQmYNpMdMG_xA,9332
|
8
|
+
auto_editor/make_layers.py,sha256=VKdBj6Kbe5CAoDIDK_MdqHVu2TXZ0sjeEbqyFTA27gI,9617
|
9
|
+
auto_editor/output.py,sha256=YgkZw0WyVfcTYH-4j6kYfvB6A1BjxGLmfOQVFi-QK_o,2561
|
9
10
|
auto_editor/preview.py,sha256=cqQdozM2IB-5qXHNxeqiSrSdEIzlMfjD4SU-NX9sYZ0,3052
|
10
|
-
auto_editor/timeline.py,sha256=
|
11
|
+
auto_editor/timeline.py,sha256=f1cxAhduoVHBTRgRwGqI3BKBb31aAVrWkEahH5gJ-0o,8379
|
11
12
|
auto_editor/vanparse.py,sha256=Ug5A2QaRqGiw4l55Z_h9T2QU1x0WqRibR7yY5rQ0WTk,10002
|
12
13
|
auto_editor/wavfile.py,sha256=afFfje8cK9lFjIkYoBbQHfvQIpsEPxWvspCtFhUKlAw,9499
|
13
14
|
auto_editor/cmds/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
14
15
|
auto_editor/cmds/cache.py,sha256=bViYbtVXefTeEIUvSanDfA6cG35ep1N_Jvtz7ZjgIkY,1959
|
15
16
|
auto_editor/cmds/desc.py,sha256=GDrKJYiHMaeTrplZAceXl1JwoqD78XsV2_5lc0Xd7po,869
|
16
|
-
auto_editor/cmds/info.py,sha256=
|
17
|
-
auto_editor/cmds/levels.py,sha256=
|
17
|
+
auto_editor/cmds/info.py,sha256=Af2aa9vW_bNfFGbRgQMqc7jj17skC6koE0XL3aF0jl0,7005
|
18
|
+
auto_editor/cmds/levels.py,sha256=EQ2hfRTe6779OtyzPIBZc5g3WhMZRddVkQWSCVV7UlE,5635
|
18
19
|
auto_editor/cmds/palet.py,sha256=ONzTqemaQq9YEfIOsDRNnwzfqnEMUMSXIQrETxyroRU,749
|
19
20
|
auto_editor/cmds/repl.py,sha256=8DgMw-XyfR5XctSmwtk4_1-zxs3ooMs72BfMRlVqLvY,3412
|
20
|
-
auto_editor/cmds/subdump.py,sha256=
|
21
|
-
auto_editor/cmds/test.py,sha256=
|
21
|
+
auto_editor/cmds/subdump.py,sha256=kHg8nfUi6I6VeJjEgMxupPa666qsYUh7ZEUxint7Gqo,2443
|
22
|
+
auto_editor/cmds/test.py,sha256=DK7T5BEtMhfrsTJSmXN_tlBKgHdajS-bICiGttq8M0c,27416
|
22
23
|
auto_editor/formats/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
23
24
|
auto_editor/formats/fcp11.py,sha256=sqjC36jI47ICPLjZJYiqGwY7foOnWOiNjkPFLdgSnI4,5208
|
24
25
|
auto_editor/formats/fcp7.py,sha256=x5cagTzGCAW3i3M6m7TZC1h8gLfSmX1UK-iiDuCpdfs,20289
|
25
|
-
auto_editor/formats/json.py,sha256=
|
26
|
+
auto_editor/formats/json.py,sha256=_dPrNr1ZC8kfSHRinG0rFudv1XFsZf2VlGAl084lMQ8,7663
|
26
27
|
auto_editor/formats/shotcut.py,sha256=-ES854LLFCMCBe100JRJedDmuk8zPev17aQMTrzPv-g,4923
|
27
28
|
auto_editor/formats/utils.py,sha256=LYXDiqOk9WwUorLGw2D0M7In9BNDkoKikNawuks7hqE,1648
|
28
29
|
auto_editor/lang/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
29
|
-
auto_editor/lang/json.py,sha256=D84vwyLtX5t5xl8S4r4jFXGVkbIg1L4IcexlS_a_k6w,9231
|
30
30
|
auto_editor/lang/libintrospection.py,sha256=6H1rGp0wqaCud5IPaoEmzULGnYt6ec7_0h32ATcw2oY,261
|
31
31
|
auto_editor/lang/libmath.py,sha256=z33A161Oe6vYYK7R6pgYjdZZe63dQkN38Qf36TL3prg,847
|
32
|
-
auto_editor/lang/palet.py,sha256=
|
33
|
-
auto_editor/lang/stdenv.py,sha256=
|
32
|
+
auto_editor/lang/palet.py,sha256=RQjyIZMJSWnzDkHTu-5mt74o9_4zO4VrcH-wLojCF7A,24113
|
33
|
+
auto_editor/lang/stdenv.py,sha256=Acf9CVXzglh3KgsJXrO7IyMMjTY5jqpz5u0QADXtDHA,44127
|
34
34
|
auto_editor/lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
35
35
|
auto_editor/lib/contracts.py,sha256=lExGQymcQUmwG5lC1lO4qm4GY8W0q_yzK_miTaAoPA4,7586
|
36
36
|
auto_editor/lib/data_structs.py,sha256=Hnzl5gWvo-geTU0g-lGejj6HQW3VvPv0NBEj2XoGskY,7089
|
37
37
|
auto_editor/lib/err.py,sha256=UlszQJdzMZwkbT8x3sY4GkCV_5x9yrd6uVVUzvA8iiI,35
|
38
38
|
auto_editor/render/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
39
|
-
auto_editor/render/audio.py,sha256=
|
40
|
-
auto_editor/render/subtitle.py,sha256=
|
41
|
-
auto_editor/render/video.py,sha256=
|
39
|
+
auto_editor/render/audio.py,sha256=7iQMtex8hzzLH80pwLD_nwN_ZH3GHjWRmER45ZVEzPk,12646
|
40
|
+
auto_editor/render/subtitle.py,sha256=F27T8OsAojUIGTGBWqTdH36h0BnHXSExxIqzOtqyZoE,6129
|
41
|
+
auto_editor/render/video.py,sha256=g2TbuCNzhbE8KsS-_3XRLLdmQKFROdwfkymwIbGmtqc,12012
|
42
42
|
auto_editor/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
43
43
|
auto_editor/utils/bar.py,sha256=Ky9JRf37JTgLyvNuIXDfucaUE8H1vBbCqKLjttmsmmo,4156
|
44
44
|
auto_editor/utils/chunks.py,sha256=J-eGKtEz68gFtRrj1kOSgH4Tj_Yz6prNQ7Xr-d9NQJw,52
|
45
45
|
auto_editor/utils/cmdkw.py,sha256=aUGBvBel2Ko1o6Rwmr4rEL-BMc5hEnzYLbyZ1GeJdcY,5729
|
46
|
-
auto_editor/utils/container.py,sha256=
|
46
|
+
auto_editor/utils/container.py,sha256=UPqlAos7UIf_ARIAbB3wuaSv1iNLFgy22YFGK8559yM,2487
|
47
47
|
auto_editor/utils/func.py,sha256=C8ucgsSEzPyBc-8obhsCXd_uQW0cnCdBn1KVxB7FHjU,2747
|
48
48
|
auto_editor/utils/log.py,sha256=wPNf6AabV-0cnoS_bPLv1Lh7llQBtNqPKeh07einOuc,3701
|
49
|
-
auto_editor/utils/types.py,sha256=
|
50
|
-
|
51
|
-
|
52
|
-
auto_editor-
|
53
|
-
auto_editor-
|
54
|
-
auto_editor-
|
55
|
-
auto_editor-
|
56
|
-
auto_editor-
|
49
|
+
auto_editor/utils/types.py,sha256=j2hd4zMQ9EftDy41Ji2_PFru_7HEZObd9yKA0BJxFaY,7616
|
50
|
+
auto_editor-27.0.0.dist-info/licenses/LICENSE,sha256=yiq99pWITHfqS0pbZMp7cy2dnbreTuvBwudsU-njvIM,1210
|
51
|
+
docs/build.py,sha256=g1uc1H9T_naGaermUiVMMwUpbT0IWElRhjgT0fvCh8w,1914
|
52
|
+
auto_editor-27.0.0.dist-info/METADATA,sha256=VhQA-UaBuv5unUT8MUVkQ_oVwGisctF3BS5tTSTkDfA,6165
|
53
|
+
auto_editor-27.0.0.dist-info/WHEEL,sha256=tTnHoFhvKQHCh4jz3yCn0WPTYIy7wXx3CJtJ7SJGV7c,91
|
54
|
+
auto_editor-27.0.0.dist-info/entry_points.txt,sha256=UAsTc7qJQbnAzHd7KWg-ALo_X9Hj2yDs3M9I2DV3eyI,212
|
55
|
+
auto_editor-27.0.0.dist-info/top_level.txt,sha256=jBV5zlbWRbKOa-xaWPvTD45QL7lGExx2BDzv-Ji4dTw,17
|
56
|
+
auto_editor-27.0.0.dist-info/RECORD,,
|
docs/build.py
CHANGED
@@ -19,13 +19,22 @@ def main():
|
|
19
19
|
parser = main_options(parser)
|
20
20
|
|
21
21
|
with open("src/ref/options.html", "w") as file:
|
22
|
-
file.write(
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
22
|
+
file.write("""\
|
23
|
+
<!DOCTYPE html>
|
24
|
+
<html lang="en">
|
25
|
+
<head>
|
26
|
+
{{ init_head }}
|
27
|
+
{{ headerdesc "Options" "These are the options and flags that auto-editor uses." }}
|
28
|
+
{{ head_icon }}
|
29
|
+
<style>
|
30
|
+
{{ core_style }}
|
31
|
+
</style>
|
32
|
+
<body>
|
33
|
+
{{ nav }}
|
34
|
+
<section class="section">
|
35
|
+
<div class="container">
|
36
|
+
""")
|
37
|
+
|
29
38
|
for op in parser.args:
|
30
39
|
if isinstance(op, OptionText):
|
31
40
|
file.write(f"<h2>{escape(op.text)}</h2>\n")
|
File without changes
|
File without changes
|
File without changes
|