auto-editor 28.1.0__py3-none-any.whl → 29.0.1__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 (60) hide show
  1. auto_editor/__init__.py +3 -1
  2. auto_editor/__main__.py +31 -497
  3. auto_editor/cli.py +12 -0
  4. {auto_editor-28.1.0.dist-info → auto_editor-29.0.1.dist-info}/METADATA +5 -6
  5. auto_editor-29.0.1.dist-info/RECORD +9 -0
  6. auto_editor-29.0.1.dist-info/entry_points.txt +2 -0
  7. {auto_editor-28.1.0.dist-info → auto_editor-29.0.1.dist-info}/top_level.txt +0 -1
  8. auto_editor/analyze.py +0 -393
  9. auto_editor/cmds/__init__.py +0 -0
  10. auto_editor/cmds/cache.py +0 -69
  11. auto_editor/cmds/desc.py +0 -32
  12. auto_editor/cmds/info.py +0 -213
  13. auto_editor/cmds/levels.py +0 -199
  14. auto_editor/cmds/palet.py +0 -29
  15. auto_editor/cmds/repl.py +0 -113
  16. auto_editor/cmds/subdump.py +0 -72
  17. auto_editor/cmds/test.py +0 -816
  18. auto_editor/edit.py +0 -560
  19. auto_editor/exports/__init__.py +0 -0
  20. auto_editor/exports/fcp11.py +0 -195
  21. auto_editor/exports/fcp7.py +0 -313
  22. auto_editor/exports/json.py +0 -63
  23. auto_editor/exports/kdenlive.py +0 -322
  24. auto_editor/exports/shotcut.py +0 -147
  25. auto_editor/ffwrapper.py +0 -187
  26. auto_editor/help.py +0 -224
  27. auto_editor/imports/__init__.py +0 -0
  28. auto_editor/imports/fcp7.py +0 -275
  29. auto_editor/imports/json.py +0 -234
  30. auto_editor/json.py +0 -297
  31. auto_editor/lang/__init__.py +0 -0
  32. auto_editor/lang/libintrospection.py +0 -10
  33. auto_editor/lang/libmath.py +0 -23
  34. auto_editor/lang/palet.py +0 -724
  35. auto_editor/lang/stdenv.py +0 -1179
  36. auto_editor/lib/__init__.py +0 -0
  37. auto_editor/lib/contracts.py +0 -235
  38. auto_editor/lib/data_structs.py +0 -278
  39. auto_editor/lib/err.py +0 -2
  40. auto_editor/make_layers.py +0 -315
  41. auto_editor/preview.py +0 -93
  42. auto_editor/render/__init__.py +0 -0
  43. auto_editor/render/audio.py +0 -517
  44. auto_editor/render/subtitle.py +0 -205
  45. auto_editor/render/video.py +0 -307
  46. auto_editor/timeline.py +0 -331
  47. auto_editor/utils/__init__.py +0 -0
  48. auto_editor/utils/bar.py +0 -142
  49. auto_editor/utils/chunks.py +0 -2
  50. auto_editor/utils/cmdkw.py +0 -206
  51. auto_editor/utils/container.py +0 -101
  52. auto_editor/utils/func.py +0 -128
  53. auto_editor/utils/log.py +0 -126
  54. auto_editor/utils/types.py +0 -277
  55. auto_editor/vanparse.py +0 -313
  56. auto_editor-28.1.0.dist-info/RECORD +0 -57
  57. auto_editor-28.1.0.dist-info/entry_points.txt +0 -6
  58. docs/build.py +0 -70
  59. {auto_editor-28.1.0.dist-info → auto_editor-29.0.1.dist-info}/WHEEL +0 -0
  60. {auto_editor-28.1.0.dist-info → auto_editor-29.0.1.dist-info}/licenses/LICENSE +0 -0
auto_editor/help.py DELETED
@@ -1,224 +0,0 @@
1
- data = {
2
- "Auto-Editor": {
3
- "_": """
4
- Auto-Editor is an automatic video/audio creator and editor. By default, it will detect silence and create a new video with those sections cut out. By changing some of the options, you can export to a traditional editor like Premiere Pro and adjust the edits there, adjust the pacing of the cuts, and change the method of editing like using audio loudness and video motion to judge making cuts.
5
-
6
- Run:
7
- auto-editor --help
8
-
9
- To get the list of options.
10
- """.strip(),
11
- "--set-speed-for-range": """
12
- This option takes 3 arguments delimited with commas and they are as follows:
13
- - speed:
14
- - How fast to play the media (number)
15
- Start:
16
- - The time when speed first gets applied (time)
17
- End:
18
- - The time when speed stops being applied (time)
19
-
20
- example:
21
-
22
- --set-range-for-speed 2.5,400,800
23
-
24
- will set the speed from 400 ticks to 800 ticks to 2.5x
25
- If timebase is 30, 400 ticks to 800 means 13.33 to 26.66 seconds
26
- """.strip(),
27
- "--edit": """
28
- Evaluates a palet expression that returns a bool-array?. The array is then used for
29
- editing.
30
-
31
- Examples:
32
- --edit audio
33
- --edit audio:0.03 ; Change the threshold. Can be a value between 0-1.
34
- --edit audio:3% ; You can also use the `%` macro.
35
- --edit audio:0.03,stream=0 ; Only consider the first stream for editing.
36
- --edit audio:stream=1,threshold=0.05 ; Here's how you use keyword arguments.
37
- --edit (or audio:0.04,stream=0 audio:0.08,stream=1) ; Consider both streams for editing (merge with logical or), but with different thresholds.
38
- --edit motion
39
- --edit motion:0.02,blur=3
40
- --edit (or audio:0.04 motion:0.02,blur=3)
41
- --edit none
42
- --edit all/e
43
-
44
- Editing Methods:
45
- - audio ; Audio silence/loudness detection
46
- - threshold threshold? : 4%
47
- - stream (or/c nat? 'all) : 'all
48
- - mincut nat? : 6
49
- - minclip nat? : 3
50
-
51
- ; mincut is more significant, there it has a larger default value.
52
- ; minclip gets applied first, then mincut
53
-
54
- - motion ; Motion detection specialized for noisy real-life videos
55
- - threshold threshold? : 2%
56
- - stream nat? : 0
57
- - blur nat? : 9
58
- - width nat1? : 400
59
-
60
- - subtitle ; Detect when subtitle matches pattern as a RegEx string.
61
- - pattern string?
62
- - stream nat? : 0
63
- - ignore-case bool? : #f
64
- - max-count (or/c nat? void?) : (void)
65
-
66
- - none ; Do not modify the media in anyway; mark all sections as "loud" (1).
67
- - all/e ; Cut out everything out; mark all sections as "silent" (0).
68
- """.strip(),
69
- "--export": """
70
- This option controls how timelines are exported.
71
-
72
- Export Methods:
73
- - default ; Export as a regular media file
74
- - premiere ; Export as an XML timeline file for Adobe Premiere Pro
75
- - name : "Auto-Editor Media Group"
76
- - resolve ; Export as an XML timeline file for DaVinci Resolve
77
- - name : "Auto-Editor Media Group"
78
- - final-cut-pro ; Export as an XML timeline file for Final Cut Pro
79
- - name : "Auto-Editor Media Group"
80
- - shotcut ; Export as an XML timeline file for Shotcut
81
- - kdenlive ; Export as an XML timeline file for kdenlive
82
- - v3 ; Export as an auto-editor v3 timeline file
83
- - v1 ; Export as an auto-editor v1 timeline file
84
- - clip-sequence ; Export as multiple numbered media files
85
-
86
- """.strip(),
87
- "--player": """
88
- This option uses shell-like syntax to support using a specific player:
89
-
90
- auto-editor in.mp4 --player mpv
91
-
92
- Args for the player program can be added as well:
93
-
94
- auto-editor in.mp4 --player 'mpv --keep-open'
95
-
96
- Absolute or relative paths can also be used in the event the player's
97
- executable can not be resolved:
98
-
99
- auto-editor in.mp4 --player '/path/to/mpv'
100
- auto-editor in.mp4 --player './my-relative-path/mpv'
101
-
102
- If --player is not set, auto-editor will use the system default.
103
- If --no-open is used, --player will always be ignored.
104
-
105
- on MacOS, QuickTime can be used as the default player this way:
106
-
107
- auto-editor in.mp4 --player 'open -a "quicktime player"'
108
- """.strip(),
109
- "--resolution": """
110
-
111
- When working with media files, resolution will be based on the first input with a
112
- fallback value of 1920x1080
113
- """.strip(),
114
- "--frame-rate": """
115
- Set the timeline's timebase and the output media's frame rate.
116
-
117
- When working with media files, frame-rate will be the first input's frame rate
118
- with a fallback value of 30
119
-
120
- The format must be a string in the form:
121
- - frame_rate_num/frame_rate_den
122
- - an integer
123
- - an floating point number
124
- - a valid frame rate label
125
-
126
- The following labels are recognized:
127
- - ntsc -> 30000/1001
128
- - ntsc_film -> 24000/1001
129
- - pal -> 25
130
- - film -> 24
131
- """.strip(),
132
- "--temp-dir": """
133
- If not set, tempdir will be set with Python's tempfile module
134
- The directory doesn't have to exist beforehand, however, the root path must be valid.
135
- Beware that the temp directory can get quite big.
136
- """.strip(),
137
- "--audio-bitrate": """
138
- `--audio-bitrate` sets the target bitrate for the audio encoder.
139
- By default, the value is `auto` (let the encoder decide).
140
- It can be set to a natural number with units: ``, `k`, `K`, `M`, or `G`.
141
-
142
- """.strip(),
143
- "--video-bitrate": """
144
- `--video-bitrate` sets the target bitrate for the video encoder. `auto` is set as the default. It accepts the same format as `--audio-bitrate`
145
- """.strip(),
146
- "--margin": """
147
- Default value: 0.2s,0.2s
148
-
149
- `--margin` takes either one number of two numbers with a `,` in-between.
150
- The numbers may be written in the 'time' format. Here is a quick recap:
151
-
152
- frames / timebase : `` (no units)
153
- seconds : `s` `sec` `secs` `second` `seconds`
154
- minutes : `min` `mins` `minute` `minutes`
155
- hours : `hour`
156
-
157
- seconds, minutes : MM:SS.SS
158
- hours, mins, secs : HH:MM:SS.SS
159
-
160
-
161
- Setting margin examples:
162
- - `--margin 6`
163
- - `--margin 4,10`
164
- - `--margin 0.3s,0.5s`
165
- - `--margin 1:12.5` ; 1 minute, 12.5 seconds
166
-
167
- Behind the scenes, margin is a function that operates on boolean arrays
168
- (where 1 represents "loud" and 0 represents "silence")
169
-
170
- Here is a list of examples on how margin mutates boolean arrays
171
-
172
- (margin 0 0 (bool-array 0 0 0 1 0 0 0))
173
- > (array 'bool 0 0 0 1 0 0 0)
174
-
175
- (margin 1 0 (bool-array 0 0 0 1 0 0 0))
176
- > (array 'bool 0 0 1 1 0 0 0)
177
-
178
- (margin 1 1 (bool-array 0 0 0 1 0 0 0))
179
- > (array 'bool 0 0 1 1 1 0 0)
180
-
181
- (margin 1 2 (bool-array 0 0 1 1 0 0 0 0 1 0))
182
- > (array 'bool 0 1 1 1 1 1 0 1 1 1)
183
-
184
- (margin -2 2 (bool-array 0 0 1 1 0 0 0))
185
- > (array 'bool 0 0 0 0 1 1 0)
186
- """.strip(),
187
- "--audio-normalize": """
188
- Apply audio normalization after cutting.
189
-
190
- Normalization Methods:
191
- - ebu ; EBU R128 (double pass) loudness normalization
192
- ; Integrated loudness target
193
- - i (and/c (or/c int? float?) (between/c -70 -5)) : -24.0
194
- ; Loudness range target
195
- - lra (and/c (or/c int? float?) (between/c 1 50)) : 7.0
196
- ; Set maximum true peak
197
- - tp (and/c (or/c int? float?) (between/c -9 0)) : -2.0
198
- ; Set offset gain. Gain is applied before the true-peak limiter
199
- - gain (and/c (or/c int? float?) (between/c -99 99)) : 0.0
200
-
201
- - peak
202
- ; Loudness target
203
- - t (and/c (or/c int? float?) (between/c -99 0)) : -8.0
204
-
205
- If `#f` is chosen, no audio-normalization will be applied.
206
-
207
- Note that this option is a thin layer over the audio filter `loudnorm` for `ebu` and `astats`/`volume` for `peak` respectively.
208
- Check out its docs for more info: https://ffmpeg.org/ffmpeg-filters.html#loudnorm
209
-
210
- Examples:
211
- --audio-normalize #f
212
- --audio-normalize ebu:i=-5,lra=40,gain=5,tp=-1
213
- """.strip(),
214
- "--silent-speed": "99999 is the 'cut speed' and values over that or <=0 are considered 'cut speeds' as well",
215
- "--video-speed": "99999 is the 'cut speed' and values over that or <=0 are considered 'cut speeds' as well",
216
- },
217
- "info": {"_": "Retrieve information and properties about media files"},
218
- "levels": {"_": "Display loudness over time"},
219
- "subdump": {
220
- "_": "Dump text-based subtitles to stdout with formatting stripped out"
221
- },
222
- "desc": {"_": "Display a media's description metadata"},
223
- "test": {"_": "Self-Hosted Unit and End-to-End tests"},
224
- }
File without changes
@@ -1,275 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import xml.etree.ElementTree as ET
4
- from fractions import Fraction
5
- from typing import TYPE_CHECKING
6
- from urllib.parse import unquote
7
- from xml.etree.ElementTree import Element
8
-
9
- from auto_editor.ffwrapper import FileInfo
10
- from auto_editor.timeline import ASpace, Clip, Template, VSpace, v3
11
-
12
- if TYPE_CHECKING:
13
- from auto_editor.utils.log import Log
14
-
15
-
16
- SUPPORTED_EFFECTS = ("timeremap",)
17
-
18
-
19
- def show(ele: Element, limit: int, depth: int = 0) -> None:
20
- print(
21
- f"{' ' * (depth * 4)}<{ele.tag} {ele.attrib}> {ele.text.strip() if ele.text is not None else ''}"
22
- )
23
- for child in ele:
24
- if isinstance(child, Element) and depth < limit:
25
- show(child, limit, depth + 1)
26
-
27
-
28
- def read_filters(clipitem: Element, log: Log) -> float:
29
- for effect_tag in clipitem:
30
- if effect_tag.tag in {"enabled", "start", "end"}:
31
- continue
32
- if len(effect_tag) < 3:
33
- log.error("<effect> requires: <effectid> <name> and one <parameter>")
34
- for i, effects in enumerate(effect_tag):
35
- if i == 0 and effects.tag != "name":
36
- log.error("<effect>: <name> must be first tag")
37
- if i == 1 and effects.tag != "effectid":
38
- log.error("<effect>: <effectid> must be second tag")
39
- if effects.text not in SUPPORTED_EFFECTS:
40
- log.error(f"`{effects.text}` is not a supported effect.")
41
-
42
- if i > 1:
43
- for j, parms in enumerate(effects):
44
- if j == 0:
45
- if parms.tag != "parameterid":
46
- log.error("<parameter>: <parameterid> must be first tag")
47
- if parms.text != "speed":
48
- break
49
-
50
- if j > 0 and parms.tag == "value":
51
- if parms.text is None:
52
- log.error("<value>: number required")
53
- return float(parms.text) / 100
54
-
55
- return 1.0
56
-
57
-
58
- def uri_to_path(uri: str) -> str:
59
- # Handle inputs like:
60
- # /Users/wyattblue/projects/auto-editor/example.mp4
61
- # file:///Users/wyattblue/projects/auto-editor/example.mp4
62
- # file:///C:/Users/WyattBlue/projects/auto-editor/example.mp4
63
- # file://localhost/Users/wyattblue/projects/auto-editor/example.mp4
64
-
65
- if uri.startswith("file://localhost/"):
66
- uri = uri[16:]
67
- elif uri.startswith("file://"):
68
- # Windows-style paths
69
- uri = uri[8:] if len(uri) > 8 and uri[9] == ":" else uri[7:]
70
- else:
71
- return uri
72
- return unquote(uri)
73
-
74
-
75
- def read_tb_ntsc(tb: int, ntsc: bool) -> Fraction:
76
- if ntsc:
77
- if tb == 24:
78
- return Fraction(24000, 1001)
79
- if tb == 30:
80
- return Fraction(30000, 1001)
81
- if tb == 60:
82
- return Fraction(60000, 1001)
83
- return tb * Fraction(999, 1000)
84
-
85
- return Fraction(tb)
86
-
87
-
88
- def fcp7_read_xml(path: str, log: Log) -> v3:
89
- def xml_bool(val: str) -> bool:
90
- if val == "TRUE":
91
- return True
92
- if val == "FALSE":
93
- return False
94
- raise TypeError("Value must be 'TRUE' or 'FALSE'")
95
-
96
- try:
97
- tree = ET.parse(path)
98
- except FileNotFoundError:
99
- log.error(f"Could not find '{path}'")
100
-
101
- root = tree.getroot()
102
-
103
- def parse(ele: Element, schema: dict) -> dict:
104
- new: dict = {}
105
- for key, val in schema.items():
106
- if isinstance(val, dict) and "__arr" in val:
107
- new[key] = []
108
-
109
- is_arr = False
110
- for child in ele:
111
- if child.tag not in schema:
112
- continue
113
-
114
- if schema[child.tag] is None:
115
- new[child.tag] = child
116
- continue
117
-
118
- if isinstance(schema[child.tag], dict):
119
- val = parse(child, schema[child.tag])
120
- is_arr = "__arr" in schema[child.tag]
121
- else:
122
- val = schema[child.tag](child.text)
123
-
124
- if child.tag in new:
125
- if not is_arr:
126
- log.error(f"<{child.tag}> can only occur once")
127
- new[child.tag].append(val)
128
- else:
129
- new[child.tag] = [val] if is_arr else val
130
-
131
- return new
132
-
133
- def check(ele: Element, tag: str) -> None:
134
- if tag != ele.tag:
135
- log.error(f"Expected '{tag}' tag, got '{ele.tag}'")
136
-
137
- check(root, "xmeml")
138
- check(root[0], "sequence")
139
- result = parse(
140
- root[0],
141
- {
142
- "name": str,
143
- "duration": int,
144
- "rate": {
145
- "timebase": Fraction,
146
- "ntsc": xml_bool,
147
- },
148
- "media": None,
149
- },
150
- )
151
-
152
- tb = read_tb_ntsc(result["rate"]["timebase"], result["rate"]["ntsc"])
153
- av = parse(
154
- result["media"],
155
- {
156
- "video": None,
157
- "audio": None,
158
- },
159
- )
160
-
161
- sources: dict[str, FileInfo] = {}
162
- vobjs: VSpace = []
163
- aobjs: ASpace = []
164
-
165
- vclip_schema = {
166
- "format": {
167
- "samplecharacteristics": {
168
- "width": int,
169
- "height": int,
170
- },
171
- },
172
- "track": {
173
- "__arr": "",
174
- "clipitem": {
175
- "__arr": "",
176
- "start": int,
177
- "end": int,
178
- "in": int,
179
- "out": int,
180
- "file": None,
181
- "filter": None,
182
- },
183
- },
184
- }
185
-
186
- aclip_schema = {
187
- "format": {"samplecharacteristics": {"samplerate": int}},
188
- "track": {
189
- "__arr": "",
190
- "clipitem": {
191
- "__arr": "",
192
- "start": int,
193
- "end": int,
194
- "in": int,
195
- "out": int,
196
- "file": None,
197
- "filter": None,
198
- },
199
- },
200
- }
201
-
202
- sr = 48000
203
- res = (1920, 1080)
204
-
205
- if "video" in av:
206
- tracks = parse(av["video"], vclip_schema)
207
-
208
- if "format" in tracks:
209
- width = tracks["format"]["samplecharacteristics"]["width"]
210
- height = tracks["format"]["samplecharacteristics"]["height"]
211
- res = width, height
212
-
213
- for t, track in enumerate(tracks["track"]):
214
- if len(track["clipitem"]) > 0:
215
- vobjs.append([])
216
- for clipitem in track["clipitem"]:
217
- file_id = clipitem["file"].attrib["id"]
218
- if file_id not in sources:
219
- fileobj = parse(clipitem["file"], {"pathurl": str})
220
-
221
- if "pathurl" in fileobj:
222
- sources[file_id] = FileInfo.init(
223
- uri_to_path(fileobj["pathurl"]),
224
- log,
225
- )
226
- else:
227
- show(clipitem["file"], 3)
228
- log.error(
229
- f"'pathurl' child element not found in {clipitem['file'].tag}"
230
- )
231
-
232
- if "filter" in clipitem:
233
- speed = read_filters(clipitem["filter"], log)
234
- else:
235
- speed = 1.0
236
-
237
- start = clipitem["start"]
238
- dur = clipitem["end"] - start
239
- offset = clipitem["in"]
240
-
241
- vobjs[t].append(
242
- Clip(start, dur, sources[file_id], offset, stream=0, speed=speed)
243
- )
244
-
245
- if "audio" in av:
246
- tracks = parse(av["audio"], aclip_schema)
247
- if "format" in tracks:
248
- sr = tracks["format"]["samplecharacteristics"]["samplerate"]
249
-
250
- for t, track in enumerate(tracks["track"]):
251
- if len(track["clipitem"]) > 0:
252
- aobjs.append([])
253
- for clipitem in track["clipitem"]:
254
- file_id = clipitem["file"].attrib["id"]
255
- if file_id not in sources:
256
- fileobj = parse(clipitem["file"], {"pathurl": str})
257
- sources[file_id] = FileInfo.init(
258
- uri_to_path(fileobj["pathurl"]), log
259
- )
260
-
261
- if "filter" in clipitem:
262
- speed = read_filters(clipitem["filter"], log)
263
- else:
264
- speed = 1.0
265
-
266
- start = clipitem["start"]
267
- dur = clipitem["end"] - start
268
- offset = clipitem["in"]
269
-
270
- aobjs[t].append(
271
- Clip(start, dur, sources[file_id], offset, stream=0, speed=speed)
272
- )
273
-
274
- T = Template.init(sources[next(iter(sources))], sr, res=res)
275
- return v3(tb, "#000", T, vobjs, aobjs, v1=None)