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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: auto-editor
3
- Version: 29.0.5
3
+ Version: 29.2.0
4
4
  Summary: Auto-Editor: Effort free video editing!
5
5
  Author-email: WyattBlue <wyattblue@auto-editor.com>
6
6
  License-Expression: Unlicense
@@ -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
- if __version__.startswith("29.0."):
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
- return binary_path
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}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: auto-editor
3
- Version: 29.0.5
3
+ Version: 29.2.0
4
4
  Summary: Auto-Editor: Effort free video editing!
5
5
  Author-email: WyattBlue <wyattblue@auto-editor.com>
6
6
  License-Expression: Unlicense
@@ -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
- self.main(
536
- ["example.mp4"], ["--audio-normalize", "ebu:i=-5,lra=20,gain=5,tp=-1"]
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