1 changed files with 155 additions and 0 deletions
@ -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()) |
|||
Loading…
Reference in new issue