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