auto-editor 28.0.2__py3-none-any.whl → 29.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-28.0.2.dist-info → auto_editor-29.0.0.dist-info}/METADATA +5 -4
- auto_editor-29.0.0.dist-info/RECORD +5 -0
- auto_editor-29.0.0.dist-info/top_level.txt +1 -0
- auto_editor/__init__.py +0 -1
- auto_editor/__main__.py +0 -503
- auto_editor/analyze.py +0 -393
- auto_editor/cmds/__init__.py +0 -0
- auto_editor/cmds/cache.py +0 -69
- auto_editor/cmds/desc.py +0 -32
- auto_editor/cmds/info.py +0 -213
- auto_editor/cmds/levels.py +0 -199
- auto_editor/cmds/palet.py +0 -29
- auto_editor/cmds/repl.py +0 -113
- auto_editor/cmds/subdump.py +0 -72
- auto_editor/cmds/test.py +0 -812
- auto_editor/edit.py +0 -548
- auto_editor/exports/__init__.py +0 -0
- auto_editor/exports/fcp11.py +0 -195
- auto_editor/exports/fcp7.py +0 -313
- auto_editor/exports/json.py +0 -63
- auto_editor/exports/shotcut.py +0 -147
- auto_editor/ffwrapper.py +0 -187
- auto_editor/help.py +0 -223
- auto_editor/imports/__init__.py +0 -0
- auto_editor/imports/fcp7.py +0 -275
- auto_editor/imports/json.py +0 -234
- auto_editor/json.py +0 -297
- auto_editor/lang/__init__.py +0 -0
- auto_editor/lang/libintrospection.py +0 -10
- auto_editor/lang/libmath.py +0 -23
- auto_editor/lang/palet.py +0 -724
- auto_editor/lang/stdenv.py +0 -1184
- auto_editor/lib/__init__.py +0 -0
- auto_editor/lib/contracts.py +0 -235
- auto_editor/lib/data_structs.py +0 -278
- auto_editor/lib/err.py +0 -2
- auto_editor/make_layers.py +0 -315
- auto_editor/preview.py +0 -93
- auto_editor/render/__init__.py +0 -0
- auto_editor/render/audio.py +0 -517
- auto_editor/render/subtitle.py +0 -205
- auto_editor/render/video.py +0 -312
- auto_editor/timeline.py +0 -331
- auto_editor/utils/__init__.py +0 -0
- auto_editor/utils/bar.py +0 -142
- auto_editor/utils/chunks.py +0 -2
- auto_editor/utils/cmdkw.py +0 -206
- auto_editor/utils/container.py +0 -102
- auto_editor/utils/func.py +0 -128
- auto_editor/utils/log.py +0 -124
- auto_editor/utils/types.py +0 -277
- auto_editor/vanparse.py +0 -313
- auto_editor-28.0.2.dist-info/RECORD +0 -56
- auto_editor-28.0.2.dist-info/entry_points.txt +0 -6
- auto_editor-28.0.2.dist-info/top_level.txt +0 -2
- docs/build.py +0 -70
- {auto_editor-28.0.2.dist-info → auto_editor-29.0.0.dist-info}/WHEEL +0 -0
- {auto_editor-28.0.2.dist-info → auto_editor-29.0.0.dist-info}/licenses/LICENSE +0 -0
auto_editor/cmds/levels.py
DELETED
@@ -1,199 +0,0 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
|
3
|
-
import sys
|
4
|
-
from dataclasses import dataclass, field
|
5
|
-
from fractions import Fraction
|
6
|
-
from typing import TYPE_CHECKING
|
7
|
-
|
8
|
-
import bv
|
9
|
-
import numpy as np
|
10
|
-
|
11
|
-
from auto_editor.analyze import *
|
12
|
-
from auto_editor.ffwrapper import FileInfo
|
13
|
-
from auto_editor.lang.palet import env
|
14
|
-
from auto_editor.lib.contracts import is_bool, is_nat, is_nat1, is_str, is_void, orc
|
15
|
-
from auto_editor.utils.bar import initBar
|
16
|
-
from auto_editor.utils.cmdkw import (
|
17
|
-
ParserError,
|
18
|
-
Required,
|
19
|
-
parse_with_palet,
|
20
|
-
pAttr,
|
21
|
-
pAttrs,
|
22
|
-
)
|
23
|
-
from auto_editor.utils.log import Log
|
24
|
-
from auto_editor.utils.types import frame_rate
|
25
|
-
from auto_editor.vanparse import ArgumentParser
|
26
|
-
|
27
|
-
if TYPE_CHECKING:
|
28
|
-
from collections.abc import Iterator
|
29
|
-
from fractions import Fraction
|
30
|
-
|
31
|
-
from numpy.typing import NDArray
|
32
|
-
|
33
|
-
|
34
|
-
@dataclass(slots=True)
|
35
|
-
class LevelArgs:
|
36
|
-
input: list[str] = field(default_factory=list)
|
37
|
-
edit: str = "audio"
|
38
|
-
timebase: Fraction | None = None
|
39
|
-
no_cache: bool = False
|
40
|
-
help: bool = False
|
41
|
-
|
42
|
-
|
43
|
-
def levels_options(parser: ArgumentParser) -> ArgumentParser:
|
44
|
-
parser.add_required("input", nargs="*")
|
45
|
-
parser.add_argument(
|
46
|
-
"--edit",
|
47
|
-
metavar="METHOD:[ATTRS?]",
|
48
|
-
help="Select the kind of detection to analyze with attributes",
|
49
|
-
)
|
50
|
-
parser.add_argument(
|
51
|
-
"--timebase",
|
52
|
-
"-tb",
|
53
|
-
metavar="NUM",
|
54
|
-
type=frame_rate,
|
55
|
-
help="Set custom timebase",
|
56
|
-
)
|
57
|
-
parser.add_argument("--no-cache", flag=True)
|
58
|
-
return parser
|
59
|
-
|
60
|
-
|
61
|
-
def print_arr(arr: NDArray) -> None:
|
62
|
-
print("")
|
63
|
-
print("@start")
|
64
|
-
if arr.dtype == np.bool_:
|
65
|
-
for a in arr:
|
66
|
-
sys.stdout.write(f"{1 if a else 0}\n")
|
67
|
-
else:
|
68
|
-
for a in arr:
|
69
|
-
sys.stdout.write(f"{a}\n")
|
70
|
-
sys.stdout.flush()
|
71
|
-
print("")
|
72
|
-
|
73
|
-
|
74
|
-
def print_arr_gen(arr: Iterator[float | np.float32]) -> None:
|
75
|
-
print("")
|
76
|
-
print("@start")
|
77
|
-
for a in arr:
|
78
|
-
print(f"{a}")
|
79
|
-
print("")
|
80
|
-
|
81
|
-
|
82
|
-
def main(sys_args: list[str] = sys.argv[1:]) -> None:
|
83
|
-
parser = levels_options(ArgumentParser("levels"))
|
84
|
-
args = parser.parse_args(LevelArgs, sys_args)
|
85
|
-
|
86
|
-
bar = initBar("none")
|
87
|
-
log = Log(quiet=True)
|
88
|
-
|
89
|
-
sources = [FileInfo.init(path, log) for path in args.input]
|
90
|
-
if len(sources) < 1:
|
91
|
-
log.error("levels needs at least one input file")
|
92
|
-
|
93
|
-
src = sources[0]
|
94
|
-
|
95
|
-
tb = src.get_fps() if args.timebase is None else args.timebase
|
96
|
-
|
97
|
-
if ":" in args.edit:
|
98
|
-
method, attrs = args.edit.split(":", 1)
|
99
|
-
else:
|
100
|
-
method, attrs = args.edit, ""
|
101
|
-
|
102
|
-
audio_builder = pAttrs("audio", pAttr("stream", 0, is_nat))
|
103
|
-
motion_builder = pAttrs(
|
104
|
-
"motion",
|
105
|
-
pAttr("stream", 0, is_nat),
|
106
|
-
pAttr("blur", 9, is_nat),
|
107
|
-
pAttr("width", 400, is_nat1),
|
108
|
-
)
|
109
|
-
subtitle_builder = pAttrs(
|
110
|
-
"subtitle",
|
111
|
-
pAttr("pattern", Required, is_str),
|
112
|
-
pAttr("stream", 0, is_nat),
|
113
|
-
pAttr("ignore-case", False, is_bool),
|
114
|
-
pAttr("max-count", None, orc(is_nat, is_void)),
|
115
|
-
)
|
116
|
-
|
117
|
-
builder_map = {
|
118
|
-
"audio": audio_builder,
|
119
|
-
"motion": motion_builder,
|
120
|
-
"subtitle": subtitle_builder,
|
121
|
-
}
|
122
|
-
|
123
|
-
for src in sources:
|
124
|
-
if method in builder_map:
|
125
|
-
try:
|
126
|
-
obj = parse_with_palet(attrs, builder_map[method], env)
|
127
|
-
except ParserError as e:
|
128
|
-
log.error(e)
|
129
|
-
|
130
|
-
levels = initLevels(src, tb, bar, False, log)
|
131
|
-
try:
|
132
|
-
if method == "audio":
|
133
|
-
if (
|
134
|
-
not args.no_cache
|
135
|
-
and (arr := levels.read_cache("audio", (obj["stream"],)))
|
136
|
-
is not None
|
137
|
-
):
|
138
|
-
print_arr(arr)
|
139
|
-
else:
|
140
|
-
container = bv.open(src.path, "r")
|
141
|
-
audio_stream = container.streams.audio[obj["stream"]]
|
142
|
-
|
143
|
-
values = []
|
144
|
-
|
145
|
-
def value_storing_generator() -> Iterator[np.float32]:
|
146
|
-
for value in iter_audio(audio_stream, tb):
|
147
|
-
values.append(value)
|
148
|
-
yield value
|
149
|
-
|
150
|
-
print_arr_gen(value_storing_generator())
|
151
|
-
container.close()
|
152
|
-
|
153
|
-
cache_array = np.array(values, dtype=np.float32)
|
154
|
-
if not args.no_cache:
|
155
|
-
levels.cache(cache_array, "audio", (obj["stream"],))
|
156
|
-
|
157
|
-
elif method == "motion":
|
158
|
-
mobj = (obj["stream"], obj["width"], obj["blur"])
|
159
|
-
if (
|
160
|
-
not args.no_cache
|
161
|
-
and (arr := levels.read_cache("motion", mobj)) is not None
|
162
|
-
):
|
163
|
-
print_arr(arr)
|
164
|
-
else:
|
165
|
-
container = bv.open(src.path, "r")
|
166
|
-
video_stream = container.streams.video[obj["stream"]]
|
167
|
-
|
168
|
-
values = []
|
169
|
-
|
170
|
-
def value_storing_generator() -> Iterator[np.float32]:
|
171
|
-
for value in iter_motion(
|
172
|
-
video_stream, tb, obj["blur"], obj["width"]
|
173
|
-
):
|
174
|
-
values.append(value)
|
175
|
-
yield value
|
176
|
-
|
177
|
-
print_arr_gen(value_storing_generator())
|
178
|
-
container.close()
|
179
|
-
|
180
|
-
cache_array = np.array(values, dtype=np.float32)
|
181
|
-
if not args.no_cache:
|
182
|
-
levels.cache(cache_array, "motion", mobj)
|
183
|
-
|
184
|
-
elif method == "subtitle":
|
185
|
-
print_arr(levels.subtitle(**obj))
|
186
|
-
elif method == "none":
|
187
|
-
print_arr(levels.none())
|
188
|
-
elif method == "all/e":
|
189
|
-
print_arr(levels.all())
|
190
|
-
else:
|
191
|
-
log.error(f"Method: {method} not supported")
|
192
|
-
except LevelError as e:
|
193
|
-
log.error(e)
|
194
|
-
|
195
|
-
log.cleanup()
|
196
|
-
|
197
|
-
|
198
|
-
if __name__ == "__main__":
|
199
|
-
main()
|
auto_editor/cmds/palet.py
DELETED
@@ -1,29 +0,0 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
|
3
|
-
import sys
|
4
|
-
|
5
|
-
from auto_editor.lang.palet import Lexer, Parser, env, interpret
|
6
|
-
from auto_editor.lang.stdenv import make_standard_env
|
7
|
-
from auto_editor.lib.err import MyError
|
8
|
-
|
9
|
-
|
10
|
-
def main(sys_args: list[str] = sys.argv[1:]) -> None:
|
11
|
-
if sys_args:
|
12
|
-
with open(sys_args[0], encoding="utf-8", errors="ignore") as file:
|
13
|
-
program_text = file.read()
|
14
|
-
|
15
|
-
env.update(make_standard_env())
|
16
|
-
try:
|
17
|
-
interpret(env, Parser(Lexer(sys_args[0], program_text)))
|
18
|
-
except (MyError, ZeroDivisionError) as e:
|
19
|
-
sys.stderr.write(f"error: {e}\n")
|
20
|
-
sys.exit(1)
|
21
|
-
|
22
|
-
else:
|
23
|
-
from .repl import main
|
24
|
-
|
25
|
-
main(sys_args)
|
26
|
-
|
27
|
-
|
28
|
-
if __name__ == "__main__":
|
29
|
-
main()
|
auto_editor/cmds/repl.py
DELETED
@@ -1,113 +0,0 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
|
3
|
-
import sys
|
4
|
-
from dataclasses import dataclass, field
|
5
|
-
from fractions import Fraction
|
6
|
-
from os import environ
|
7
|
-
|
8
|
-
import auto_editor
|
9
|
-
from auto_editor.analyze import initLevels
|
10
|
-
from auto_editor.ffwrapper import FileInfo
|
11
|
-
from auto_editor.lang.palet import ClosingError, Lexer, Parser, env, interpret
|
12
|
-
from auto_editor.lang.stdenv import make_standard_env
|
13
|
-
from auto_editor.lib.data_structs import print_str
|
14
|
-
from auto_editor.lib.err import MyError
|
15
|
-
from auto_editor.utils.bar import initBar
|
16
|
-
from auto_editor.utils.log import Log
|
17
|
-
from auto_editor.utils.types import frame_rate
|
18
|
-
from auto_editor.vanparse import ArgumentParser
|
19
|
-
|
20
|
-
try:
|
21
|
-
import readline # noqa
|
22
|
-
except ImportError:
|
23
|
-
pass
|
24
|
-
|
25
|
-
|
26
|
-
@dataclass(slots=True)
|
27
|
-
class REPL_Args:
|
28
|
-
input: list[str] = field(default_factory=list)
|
29
|
-
debug_parser: bool = False
|
30
|
-
timebase: Fraction | None = None
|
31
|
-
ffmpeg_location: str | None = None
|
32
|
-
my_ffmpeg: bool = False
|
33
|
-
temp_dir: str | None = None
|
34
|
-
help: bool = False
|
35
|
-
|
36
|
-
|
37
|
-
def repl_options(parser: ArgumentParser) -> ArgumentParser:
|
38
|
-
parser.add_required("input", nargs="*")
|
39
|
-
parser.add_argument(
|
40
|
-
"--debug-parser",
|
41
|
-
flag=True,
|
42
|
-
help="Print parser value",
|
43
|
-
)
|
44
|
-
parser.add_argument(
|
45
|
-
"--timebase",
|
46
|
-
"-tb",
|
47
|
-
metavar="NUM",
|
48
|
-
type=frame_rate,
|
49
|
-
help="Set custom timebase",
|
50
|
-
)
|
51
|
-
return parser
|
52
|
-
|
53
|
-
|
54
|
-
def main(sys_args: list[str] = sys.argv[1:]) -> None:
|
55
|
-
args = repl_options(ArgumentParser(None)).parse_args(REPL_Args, sys_args)
|
56
|
-
|
57
|
-
if args.input:
|
58
|
-
log = Log(quiet=True)
|
59
|
-
sources = [FileInfo.init(path, log) for path in args.input]
|
60
|
-
src = sources[0]
|
61
|
-
tb = src.get_fps() if args.timebase is None else args.timebase
|
62
|
-
env["timebase"] = tb
|
63
|
-
env["@levels"] = initLevels(src, tb, initBar("modern"), False, log)
|
64
|
-
|
65
|
-
env.update(make_standard_env())
|
66
|
-
print(f"Auto-Editor {auto_editor.__version__}")
|
67
|
-
text = None
|
68
|
-
|
69
|
-
no_color = bool(environ.get("NO_COLOR") or environ.get("AV_LOG_FORCE_NOCOLOR"))
|
70
|
-
if no_color:
|
71
|
-
bold_pink = bold_red = reset = ""
|
72
|
-
else:
|
73
|
-
bold_pink = "\033[1;95m"
|
74
|
-
bold_red = "\033[1;31m"
|
75
|
-
reset = "\033[0m"
|
76
|
-
|
77
|
-
try:
|
78
|
-
while True:
|
79
|
-
try:
|
80
|
-
if text is None:
|
81
|
-
text = input(f"{bold_pink}>{reset} ")
|
82
|
-
else:
|
83
|
-
text += "\n" + input(" ")
|
84
|
-
except KeyboardInterrupt as e:
|
85
|
-
if text is None:
|
86
|
-
raise e
|
87
|
-
text = None
|
88
|
-
print("")
|
89
|
-
continue
|
90
|
-
|
91
|
-
try:
|
92
|
-
parser = Parser(Lexer("repl", text))
|
93
|
-
if args.debug_parser:
|
94
|
-
print(f"parser: {parser}")
|
95
|
-
|
96
|
-
for result in interpret(env, parser):
|
97
|
-
if result is not None:
|
98
|
-
sys.stdout.write(f"{print_str(result)}\n")
|
99
|
-
env["_"] = result
|
100
|
-
|
101
|
-
except ClosingError:
|
102
|
-
continue # Allow user to continue adding text
|
103
|
-
except MyError as e:
|
104
|
-
print(f"{bold_red}error{reset}: {e}")
|
105
|
-
|
106
|
-
text = None
|
107
|
-
|
108
|
-
except (KeyboardInterrupt, EOFError):
|
109
|
-
print("")
|
110
|
-
|
111
|
-
|
112
|
-
if __name__ == "__main__":
|
113
|
-
main()
|
auto_editor/cmds/subdump.py
DELETED
@@ -1,72 +0,0 @@
|
|
1
|
-
import sys
|
2
|
-
from dataclasses import dataclass, field
|
3
|
-
|
4
|
-
import bv
|
5
|
-
from bv.subtitles.subtitle import AssSubtitle
|
6
|
-
|
7
|
-
from auto_editor.json import dump
|
8
|
-
from auto_editor.vanparse import ArgumentParser
|
9
|
-
|
10
|
-
|
11
|
-
@dataclass(slots=True)
|
12
|
-
class SubdumpArgs:
|
13
|
-
help: bool = False
|
14
|
-
input: list[str] = field(default_factory=list)
|
15
|
-
json: bool = False
|
16
|
-
|
17
|
-
|
18
|
-
def main(sys_args: list[str] = sys.argv[1:]) -> None:
|
19
|
-
parser = ArgumentParser("subdump")
|
20
|
-
parser.add_required("input", nargs="*")
|
21
|
-
parser.add_argument("--json", flag=True)
|
22
|
-
args = parser.parse_args(SubdumpArgs, sys_args)
|
23
|
-
|
24
|
-
if args.json:
|
25
|
-
data = {}
|
26
|
-
for input_file in args.input:
|
27
|
-
container = bv.open(input_file)
|
28
|
-
for s in range(len(container.streams.subtitles)):
|
29
|
-
entry_data = []
|
30
|
-
|
31
|
-
input_stream = container.streams.subtitles[s]
|
32
|
-
assert input_stream.time_base is not None
|
33
|
-
for packet in container.demux(input_stream):
|
34
|
-
if (
|
35
|
-
packet.dts is None
|
36
|
-
or packet.pts is None
|
37
|
-
or packet.duration is None
|
38
|
-
):
|
39
|
-
continue
|
40
|
-
|
41
|
-
start = packet.pts * input_stream.time_base
|
42
|
-
end = start + packet.duration * input_stream.time_base
|
43
|
-
|
44
|
-
startf = round(float(start), 3)
|
45
|
-
endf = round(float(end), 3)
|
46
|
-
|
47
|
-
if endf - startf <= 0.02:
|
48
|
-
continue
|
49
|
-
|
50
|
-
for sub in packet.decode():
|
51
|
-
if isinstance(sub, AssSubtitle):
|
52
|
-
content = sub.dialogue.decode("utf-8", errors="ignore")
|
53
|
-
entry_data.append([startf, endf, content])
|
54
|
-
|
55
|
-
data[f"{input_file}:{s}"] = entry_data
|
56
|
-
container.close()
|
57
|
-
|
58
|
-
dump(data, sys.stdout, indent=4)
|
59
|
-
return
|
60
|
-
|
61
|
-
for input_file in args.input:
|
62
|
-
with bv.open(input_file) as container:
|
63
|
-
for s in range(len(container.streams.subtitles)):
|
64
|
-
print(f"file: {input_file} ({s}:{container.streams.subtitles[s].name})")
|
65
|
-
for sub2 in container.decode(subtitles=s):
|
66
|
-
if isinstance(sub2, AssSubtitle):
|
67
|
-
print(sub2.ass.decode("utf-8", errors="ignore"))
|
68
|
-
print("------")
|
69
|
-
|
70
|
-
|
71
|
-
if __name__ == "__main__":
|
72
|
-
main()
|