diff --git a/video-splitter.py b/video-splitter.py new file mode 100644 index 0000000..c195e7c --- /dev/null +++ b/video-splitter.py @@ -0,0 +1,155 @@ +#!/usr/bin/env python3 + +import sys +import os +import subprocess +from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QPushButton, + QFileDialog, QLabel, QLineEdit, QProgressBar) +from PyQt6.QtCore import QThread, pyqtSignal + +class SplitWorker(QThread): + progress = pyqtSignal(str) + finished = pyqtSignal() + + def __init__(self, input_file, size_limit_mb, output_dir): + super().__init__() + self.input_file = input_file + self.size_limit = size_limit_mb * 1000000 # Convert MB to bytes + self.output_dir = output_dir + + def run(self): + # Extract basename and set output pattern + basename = os.path.splitext(os.path.basename(self.input_file))[0] + output_pattern = os.path.join(self.output_dir, f"{basename}-%d.mp4") + + # Get total duration + duration_cmd = [ + "ffprobe", "-i", self.input_file, "-show_entries", "format=duration", + "-v", "quiet", "-of", "default=noprint_wrappers=1:nokey=1" + ] + duration = float(subprocess.check_output(duration_cmd).decode().strip().split(".")[0]) + + cur_duration = 0 + i = 1 + + while cur_duration < duration: + output_file = os.path.join(self.output_dir, f"{basename}-{i}.mp4") + ffmpeg_cmd = [ + "ffmpeg", "-ss", str(cur_duration), "-i", self.input_file, + "-fs", str(self.size_limit), "-c", "copy", "-y", output_file + ] + subprocess.run(ffmpeg_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + # Get duration of the new chunk + new_duration_cmd = [ + "ffprobe", "-i", output_file, "-show_entries", "format=duration", + "-v", "quiet", "-of", "default=noprint_wrappers=1:nokey=1" + ] + new_duration = float(subprocess.check_output(new_duration_cmd).decode().strip().split(".")[0]) + + cur_duration += new_duration + self.progress.emit(f"Created chunk {i} ({cur_duration}/{duration} seconds processed)") + i += 1 + + self.finished.emit() + +class VideoSplitterGUI(QMainWindow): + def __init__(self): + super().__init__() + self.setWindowTitle("Video Splitter") + self.setGeometry(100, 100, 400, 300) + + # Main widget and layout + widget = QWidget() + self.setCentralWidget(widget) + layout = QVBoxLayout() + widget.setLayout(layout) + + # Input file selection + self.input_label = QLabel("No file selected") + self.select_input_btn = QPushButton("Select MP4 File") + self.select_input_btn.clicked.connect(self.select_input_file) + layout.addWidget(self.input_label) + layout.addWidget(self.select_input_btn) + + # Size limit input (in MB) + self.size_label = QLabel("Chunk Size (MB):") + self.size_input = QLineEdit("110") # Default 110 MB + layout.addWidget(self.size_label) + layout.addWidget(self.size_input) + + # Output directory selection + self.output_label = QLabel("Output Directory: Current directory") + self.select_output_btn = QPushButton("Select Output Directory") + self.select_output_btn.clicked.connect(self.select_output_dir) + layout.addWidget(self.output_label) + layout.addWidget(self.select_output_btn) + + # Start button + self.start_btn = QPushButton("Start Splitting") + self.start_btn.clicked.connect(self.start_splitting) + layout.addWidget(self.start_btn) + + # Progress + self.progress_label = QLabel("Ready") + self.progress_bar = QProgressBar() + self.progress_bar.setMinimum(0) + self.progress_bar.setMaximum(100) + layout.addWidget(self.progress_label) + layout.addWidget(self.progress_bar) + + # Stretch to push content up + layout.addStretch() + + # Variables + self.input_file = "" + self.output_dir = os.getcwd() + + def select_input_file(self): + file, _ = QFileDialog.getOpenFileName(self, "Select MP4 File", "", "MP4 Files (*.mp4)") + if file: + self.input_file = file + self.input_label.setText(f"Selected: {os.path.basename(file)}") + + def select_output_dir(self): + dir = QFileDialog.getExistingDirectory(self, "Select Output Directory") + if dir: + self.output_dir = dir + self.output_label.setText(f"Output Directory: {dir}") + + def start_splitting(self): + if not self.input_file: + self.progress_label.setText("Error: No input file selected") + return + + size_limit_mb = self.size_input.text() + try: + size_limit_mb = float(size_limit_mb) # Allow decimals like 110.5 MB + if size_limit_mb <= 0: + raise ValueError + except ValueError: + self.progress_label.setText("Error: Invalid size limit (must be a positive number)") + return + + self.start_btn.setEnabled(False) + self.progress_label.setText("Splitting in progress...") + self.worker = SplitWorker(self.input_file, size_limit_mb, self.output_dir) + self.worker.progress.connect(self.update_progress) + self.worker.finished.connect(self.split_finished) + self.worker.start() + + def update_progress(self, message): + self.progress_label.setText(message) + # Simple progress approximation (could be enhanced with actual file size checks) + self.progress_bar.setValue(self.progress_bar.value() + 10) + + def split_finished(self): + self.progress_label.setText("Splitting complete!") + self.progress_bar.setValue(100) + self.start_btn.setEnabled(True) + +if __name__ == "__main__": + app = QApplication(sys.argv) + window = VideoSplitterGUI() + window.show() + sys.exit(app.exec())