You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
155 lines
5.7 KiB
155 lines
5.7 KiB
#!/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())
|
|
|