peg-this 3.0.2__py3-none-any.whl → 4.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.
@@ -0,0 +1,83 @@
1
+
2
+ import os
3
+ from pathlib import Path
4
+
5
+ import ffmpeg
6
+ import questionary
7
+ from rich.console import Console
8
+
9
+ from peg_this.utils.ffmpeg_utils import run_command
10
+ from peg_this.utils.ui_utils import get_media_files
11
+
12
+ console = Console()
13
+
14
+
15
+ def join_videos():
16
+ """Join multiple videos into a single file after standardizing their resolutions and sample rates."""
17
+ console.print("[bold cyan]Select videos to join (in order). Press Enter when done.[/bold cyan]")
18
+
19
+ media_files = get_media_files()
20
+ video_files = [f for f in media_files if Path(f).suffix.lower() in [".mp4", ".mkv", ".mov", ".avi", ".webm"]]
21
+
22
+ if len(video_files) < 2:
23
+ console.print("[bold yellow]Not enough video files in the directory to join.[/bold yellow]")
24
+ questionary.press_any_key_to_continue().ask()
25
+ return
26
+
27
+ selected_videos = questionary.checkbox("Select at least two videos to join in order:", choices=video_files).ask()
28
+
29
+ if not selected_videos or len(selected_videos) < 2:
30
+ console.print("[bold yellow]Joining cancelled. At least two videos must be selected.[/bold yellow]")
31
+ return
32
+
33
+ console.print("Videos will be joined in this order:")
34
+ for i, video in enumerate(selected_videos):
35
+ console.print(f" {i+1}. {video}")
36
+
37
+ output_file = questionary.text("Enter the output file name:", default="joined_video.mp4").ask()
38
+ if not output_file: return
39
+
40
+ try:
41
+ first_video_path = os.path.abspath(selected_videos[0])
42
+ probe = ffmpeg.probe(first_video_path)
43
+ video_info = next(s for s in probe['streams'] if s['codec_type'] == 'video')
44
+ audio_info = next(s for s in probe['streams'] if s['codec_type'] == 'audio')
45
+
46
+ target_width = video_info['width']
47
+ target_height = video_info['height']
48
+ target_sar = video_info.get('sample_aspect_ratio', '1:1')
49
+ target_sample_rate = audio_info['sample_rate']
50
+
51
+ except Exception as e:
52
+ console.print(f"[bold red]Could not probe first video for target parameters: {e}[/bold red]")
53
+ return
54
+
55
+ console.print(f"Standardizing all videos to: {target_width}x{target_height} resolution and {target_sample_rate} Hz audio.")
56
+
57
+ processed_streams = []
58
+ for video_file in selected_videos:
59
+ stream = ffmpeg.input(os.path.abspath(video_file))
60
+ v = (
61
+ stream.video
62
+ .filter('scale', w=target_width, h=target_height, force_original_aspect_ratio='decrease')
63
+ .filter('pad', w=target_width, h=target_height, x='(ow-iw)/2', y='(oh-ih)/2')
64
+ .filter('setsar', sar=target_sar.replace(':','/'))
65
+ .filter('setpts', 'PTS-STARTPTS')
66
+ )
67
+ a = (
68
+ stream.audio
69
+ .filter('aresample', sample_rate=target_sample_rate)
70
+ .filter('asetpts', 'PTS-STARTPTS')
71
+ )
72
+ processed_streams.append(v)
73
+ processed_streams.append(a)
74
+
75
+ joined = ffmpeg.concat(*processed_streams, v=1, a=1).node
76
+ output_stream = ffmpeg.output(joined[0], joined[1], output_file, **{'c:v': 'libx264', 'crf': 23, 'c:a': 'aac', 'b:a': '192k', 'y': None})
77
+
78
+ if run_command(output_stream, "Joining and re-encoding videos...", show_progress=True):
79
+ console.print(f"[bold green]Successfully joined videos into {output_file}[/bold green]")
80
+ else:
81
+ console.print("[bold red]Failed to join videos.[/bold red]")
82
+
83
+ questionary.press_any_key_to_continue().ask()
@@ -0,0 +1,26 @@
1
+
2
+ from pathlib import Path
3
+
4
+ import ffmpeg
5
+ import questionary
6
+ from rich.console import Console
7
+
8
+ from peg_this.utils.ffmpeg_utils import run_command
9
+
10
+ console = Console()
11
+
12
+
13
+ def trim_video(file_path):
14
+ """Cut a video by specifying start and end times."""
15
+ start_time = questionary.text("Enter start time (HH:MM:SS or seconds):").ask()
16
+ if not start_time: return
17
+ end_time = questionary.text("Enter end time (HH:MM:SS or seconds):").ask()
18
+ if not end_time: return
19
+
20
+ output_file = f"{Path(file_path).stem}_trimmed{Path(file_path).suffix}"
21
+
22
+ stream = ffmpeg.input(file_path, ss=start_time, to=end_time).output(output_file, c='copy', y=None)
23
+
24
+ run_command(stream, "Trimming video...", show_progress=True)
25
+ console.print(f"[bold green]Successfully trimmed to {output_file}[/bold green]")
26
+ questionary.press_any_key_to_continue().ask()