auto-editor 29.0.5__tar.gz → 29.2.0__tar.gz
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-29.0.5 → auto_editor-29.2.0}/PKG-INFO +1 -1
- auto_editor-29.2.0/auto_editor/__init__.py +1 -0
- {auto_editor-29.0.5 → auto_editor-29.2.0}/auto_editor/__main__.py +19 -9
- {auto_editor-29.0.5 → auto_editor-29.2.0}/auto_editor.egg-info/PKG-INFO +1 -1
- {auto_editor-29.0.5 → auto_editor-29.2.0}/pyproject.toml +4 -1
- {auto_editor-29.0.5 → auto_editor-29.2.0}/tests/test.py +86 -2
- auto_editor-29.0.5/auto_editor/__init__.py +0 -1
- {auto_editor-29.0.5 → auto_editor-29.2.0}/LICENSE +0 -0
- {auto_editor-29.0.5 → auto_editor-29.2.0}/README.md +0 -0
- {auto_editor-29.0.5 → auto_editor-29.2.0}/auto_editor.egg-info/SOURCES.txt +0 -0
- {auto_editor-29.0.5 → auto_editor-29.2.0}/auto_editor.egg-info/dependency_links.txt +0 -0
- {auto_editor-29.0.5 → auto_editor-29.2.0}/auto_editor.egg-info/entry_points.txt +0 -0
- {auto_editor-29.0.5 → auto_editor-29.2.0}/auto_editor.egg-info/top_level.txt +0 -0
- {auto_editor-29.0.5 → auto_editor-29.2.0}/setup.cfg +0 -0
@@ -0,0 +1 @@
|
|
1
|
+
__version__ = "29.2.0"
|
@@ -1,5 +1,3 @@
|
|
1
|
-
"""Main entry point for auto-editor when run as a module."""
|
2
|
-
|
3
1
|
import platform
|
4
2
|
import subprocess
|
5
3
|
import sys
|
@@ -8,14 +6,10 @@ from pathlib import Path
|
|
8
6
|
|
9
7
|
from . import __version__
|
10
8
|
|
11
|
-
|
12
|
-
version = "29.0.0"
|
13
|
-
else:
|
14
|
-
version = __version__
|
9
|
+
version = __version__
|
15
10
|
|
16
11
|
|
17
12
|
def get_binary_info():
|
18
|
-
"""Get the appropriate binary name and download URL for this platform."""
|
19
13
|
system = platform.system().lower()
|
20
14
|
machine = platform.machine().lower()
|
21
15
|
|
@@ -34,11 +28,23 @@ def get_binary_info():
|
|
34
28
|
else:
|
35
29
|
raise RuntimeError(f"Unsupported platform: {system} {machine}")
|
36
30
|
|
37
|
-
# Use the package version to construct the download URL
|
38
31
|
url = f"https://github.com/WyattBlue/auto-editor/releases/download/{version}/{binary_name}"
|
39
32
|
return binary_name, local_name, url
|
40
33
|
|
41
34
|
|
35
|
+
def get_binary_version(binary_path):
|
36
|
+
try:
|
37
|
+
result = subprocess.run(
|
38
|
+
[str(binary_path), "--version"],
|
39
|
+
capture_output=True,
|
40
|
+
text=True,
|
41
|
+
timeout=5,
|
42
|
+
)
|
43
|
+
return result.stdout.strip()
|
44
|
+
except Exception:
|
45
|
+
return None
|
46
|
+
|
47
|
+
|
42
48
|
def download_binary():
|
43
49
|
"""Download the appropriate binary from GitHub releases."""
|
44
50
|
package_dir = Path(__file__).parent
|
@@ -49,7 +55,11 @@ def download_binary():
|
|
49
55
|
binary_path = bin_dir / local_name
|
50
56
|
|
51
57
|
if binary_path.exists():
|
52
|
-
|
58
|
+
binary_version = get_binary_version(binary_path)
|
59
|
+
if binary_version == version:
|
60
|
+
return binary_path
|
61
|
+
print(f"Removing outdated version ({binary_version})...")
|
62
|
+
binary_path.unlink()
|
53
63
|
|
54
64
|
print("Downloading auto-editor binary for your platform...")
|
55
65
|
print(f"URL: {url}")
|
@@ -3,7 +3,6 @@ requires = ["setuptools>=77"]
|
|
3
3
|
|
4
4
|
[project]
|
5
5
|
name = "auto-editor"
|
6
|
-
version = "29.0.5"
|
7
6
|
description = "Auto-Editor: Effort free video editing!"
|
8
7
|
readme = "README.md"
|
9
8
|
license = "Unlicense"
|
@@ -15,6 +14,7 @@ keywords = [
|
|
15
14
|
"processing", "nonlinear", "automatic", "silence-detect",
|
16
15
|
"silence-removal", "silence-speedup", "motion-detection",
|
17
16
|
]
|
17
|
+
dynamic = ["version"]
|
18
18
|
|
19
19
|
[project.scripts]
|
20
20
|
auto-editor = "auto_editor.__main__:main"
|
@@ -22,6 +22,9 @@ auto-editor = "auto_editor.__main__:main"
|
|
22
22
|
[tool.setuptools.packages.find]
|
23
23
|
include = ["auto_editor*"]
|
24
24
|
|
25
|
+
[tool.setuptools.dynamic]
|
26
|
+
version = {attr = "auto_editor.__version__"}
|
27
|
+
|
25
28
|
[project.urls]
|
26
29
|
"Bug Tracker" = "https://github.com/WyattBlue/auto-editor/discussions"
|
27
30
|
"Source Code" = "https://github.com/WyattBlue/auto-editor"
|
@@ -272,6 +272,7 @@ class Runner:
|
|
272
272
|
input = ["resources/only-video/man-on-green-screen.gif"]
|
273
273
|
out = self.main(input, ["--edit", "none", "--cut-out", "2sec,end"], "out.gif")
|
274
274
|
assert fileinfo(out).videos[0].codec == "gif"
|
275
|
+
assert len(fileinfo(out).audios) == 0
|
275
276
|
|
276
277
|
def test_margin(self):
|
277
278
|
self.main(["example.mp4"], ["-m", "3"])
|
@@ -532,10 +533,93 @@ class Runner:
|
|
532
533
|
self.main(["example.mp4"], ["--audio-normalize", "#f"])
|
533
534
|
|
534
535
|
def test_audio_norm_ebu(self) -> None:
|
535
|
-
|
536
|
-
|
536
|
+
"""Test that EBU normalization preserves correct pitch/duration."""
|
537
|
+
import wave
|
538
|
+
import struct
|
539
|
+
import hashlib
|
540
|
+
|
541
|
+
out_ebu = self.main(
|
542
|
+
["example.mp4"],
|
543
|
+
["--audio-normalize", "ebu:i=-5,lra=20,gain=5,tp=-1"],
|
544
|
+
"ebu_out.wav",
|
545
|
+
)
|
546
|
+
out_none = self.main(
|
547
|
+
["example.mp4"], ["--audio-normalize", "#f"], "no_norm_out.wav"
|
537
548
|
)
|
538
549
|
|
550
|
+
with (
|
551
|
+
wave.open(out_ebu, "rb") as ebu_file,
|
552
|
+
wave.open(out_none, "rb") as none_file,
|
553
|
+
):
|
554
|
+
ebu_sr = ebu_file.getframerate()
|
555
|
+
ebu_frames = ebu_file.getnframes()
|
556
|
+
ebu_chl = ebu_file.getnchannels()
|
557
|
+
|
558
|
+
none_sr = none_file.getframerate()
|
559
|
+
none_frames = none_file.getnframes()
|
560
|
+
none_chl = none_file.getnchannels()
|
561
|
+
|
562
|
+
assert ebu_sr == none_sr == 48000, f"sr differ: EBU={ebu_sr}, #f={none_sr}"
|
563
|
+
assert ebu_chl == none_chl == 2, f"{ebu_chl=} {none_chl=}"
|
564
|
+
|
565
|
+
# Frame counts should match (no resampling/pitch shift)
|
566
|
+
assert ebu_frames == none_frames, (
|
567
|
+
f"Frame count mismatch: EBU={ebu_frames}, #f={none_frames}"
|
568
|
+
)
|
569
|
+
duration = ebu_frames / ebu_sr
|
570
|
+
assert 17.0 < duration < 17.8
|
571
|
+
|
572
|
+
middle_pos = ebu_frames // 2
|
573
|
+
ebu_file.setpos(middle_pos)
|
574
|
+
none_file.setpos(middle_pos)
|
575
|
+
|
576
|
+
ebu_data = ebu_file.readframes(1000)
|
577
|
+
none_data = none_file.readframes(1000)
|
578
|
+
|
579
|
+
ebu_samples = struct.unpack(f"{len(ebu_data) // 2}h", ebu_data)
|
580
|
+
none_samples = struct.unpack(f"{len(none_data) // 2}h", none_data)
|
581
|
+
|
582
|
+
assert max(abs(s) for s in ebu_samples) > 100, "EBU output is silent"
|
583
|
+
assert max(abs(s) for s in none_samples) > 100, "Non-norm output is silent"
|
584
|
+
|
585
|
+
def test_audio_norm_peak(self) -> None:
|
586
|
+
"""Test that peak normalization increases loudness in the output."""
|
587
|
+
import wave
|
588
|
+
import struct
|
589
|
+
|
590
|
+
out = self.main(
|
591
|
+
["example.mp4"], ["--audio-normalize", "peak:-3"], "peak_out.wav"
|
592
|
+
)
|
593
|
+
|
594
|
+
with wave.open(out, "rb") as wav_file:
|
595
|
+
n_channels = wav_file.getnchannels()
|
596
|
+
sample_width = wav_file.getsampwidth()
|
597
|
+
n_frames = wav_file.getnframes()
|
598
|
+
|
599
|
+
frames = wav_file.readframes(n_frames)
|
600
|
+
|
601
|
+
assert sample_width == 2 # 16-bit audio
|
602
|
+
samples = struct.unpack(f"{n_frames * n_channels}h", frames)
|
603
|
+
max_amplitude = max(abs(s) for s in samples)
|
604
|
+
# For peak:-3dB, we expect the peak to be close to -3dB
|
605
|
+
# which is about 70.7% of max (10^(-3/20) ≈ 0.707), Allow some tolerance
|
606
|
+
assert max_amplitude > 15000, f"Peak amplitude too low: {max_amplitude}"
|
607
|
+
|
608
|
+
def test_wav_output(self) -> None:
|
609
|
+
"""Test that converting to WAV output produces a valid PCM file."""
|
610
|
+
out = self.main(["example.mp4"], [], "out.wav")
|
611
|
+
# Verify the output file is a valid media file with PCM audio
|
612
|
+
with av.open(out) as container:
|
613
|
+
assert len(container.streams) == 1
|
614
|
+
audio = container.streams[0]
|
615
|
+
assert isinstance(audio, AudioStream)
|
616
|
+
# Should be PCM codec, not AAC
|
617
|
+
assert audio.codec.name.startswith("pcm_"), (
|
618
|
+
f"Expected PCM codec, got {audio.codec.name}"
|
619
|
+
)
|
620
|
+
assert audio.sample_rate == 48000
|
621
|
+
assert audio.channels == 2
|
622
|
+
|
539
623
|
|
540
624
|
def run_tests(tests: list[Callable], args) -> None:
|
541
625
|
if args.only != []:
|
@@ -1 +0,0 @@
|
|
1
|
-
__version__ = "29.0.5"
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|