- Added app.py for subtitle positioning tool using Tkinter and MoviePy. - Integrated font selection and adjustable subtitle positioning. - Implemented loading and saving of presets in JSON format. - Added functionality to preview subtitles on video clips. - Enhanced subtitle rendering with highlight effects. - Created app2.py for advanced subtitle handling with SRT file support. - Implemented SRT parsing and subtitle navigation in app2.py. - Added system font detection for better font compatibility. - Updated shorts_generator2.py to include GUI for shorts generation. - Enhanced error handling and progress tracking in shorts generation. - Created subtitle_generator.py for automatic subtitle generation from video. - Added progress bar and user feedback in subtitle generation GUI. - Updated subtitle_gui_presets.json and subtitles.srt for testing.
156 lines
4.6 KiB
Python
156 lines
4.6 KiB
Python
import os
|
|
import math
|
|
import tempfile
|
|
import moviepy as mp
|
|
import speech_recognition as sr
|
|
import tkinter as tk
|
|
from tkinter import filedialog, messagebox, ttk
|
|
|
|
|
|
def format_time(seconds):
|
|
hours = int(seconds // 3600)
|
|
minutes = int((seconds % 3600) // 60)
|
|
secs = int(seconds % 60)
|
|
millis = int((seconds - int(seconds)) * 1000)
|
|
return f"{hours:02}:{minutes:02}:{secs:02},{millis:03}"
|
|
|
|
|
|
def wrap_text(text, max_len=40):
|
|
"""
|
|
Wraps text to ~max_len characters per line without cutting words.
|
|
"""
|
|
words = text.split()
|
|
lines = []
|
|
current_line = ""
|
|
|
|
for word in words:
|
|
if len(current_line + " " + word) <= max_len:
|
|
current_line += (" " if current_line else "") + word
|
|
else:
|
|
lines.append(current_line)
|
|
current_line = word
|
|
|
|
if current_line:
|
|
lines.append(current_line)
|
|
|
|
return "\n".join(lines)
|
|
|
|
|
|
def write_srt(subtitles, output_path):
|
|
with open(output_path, 'w', encoding='utf-8') as f:
|
|
for i, sub in enumerate(subtitles, 1):
|
|
f.write(f"{i}\n")
|
|
f.write(f"{format_time(sub['start'])} --> {format_time(sub['end'])}\n")
|
|
f.write(f"{wrap_text(sub['text'])}\n\n")
|
|
|
|
|
|
def transcribe_video_to_srt(video_path, srt_output_path, progress_callback=None, chunk_duration=10):
|
|
try:
|
|
video = mp.VideoFileClip(video_path)
|
|
audio = video.audio
|
|
|
|
with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as temp_audio_file:
|
|
temp_audio_path = temp_audio_file.name
|
|
audio.write_audiofile(temp_audio_path, logger=None)
|
|
|
|
recognizer = sr.Recognizer()
|
|
subtitles = []
|
|
|
|
with sr.AudioFile(temp_audio_path) as source:
|
|
audio_duration = source.DURATION
|
|
num_chunks = math.ceil(audio_duration / chunk_duration)
|
|
|
|
for i in range(num_chunks):
|
|
start_time = i * chunk_duration
|
|
end_time = min((i + 1) * chunk_duration, audio_duration)
|
|
|
|
source_offset = start_time
|
|
duration = end_time - start_time
|
|
|
|
audio_data = recognizer.record(source, offset=source_offset, duration=duration)
|
|
|
|
try:
|
|
text = recognizer.recognize_google(audio_data)
|
|
subtitles.append({
|
|
"start": start_time,
|
|
"end": end_time,
|
|
"text": text
|
|
})
|
|
except sr.UnknownValueError:
|
|
pass
|
|
except sr.RequestError as e:
|
|
print(f"API error: {e}")
|
|
|
|
# Update progress bar
|
|
if progress_callback:
|
|
progress_callback(i + 1, num_chunks)
|
|
|
|
os.remove(temp_audio_path)
|
|
write_srt(subtitles, srt_output_path)
|
|
return True
|
|
except Exception as e:
|
|
print(f"Error: {e}")
|
|
return False
|
|
|
|
|
|
# -------------------- GUI --------------------
|
|
|
|
def select_file_and_generate():
|
|
video_path = filedialog.askopenfilename(
|
|
title="Select a video file",
|
|
filetypes=[("Video files", "*.mp4 *.mov *.avi *.mkv")]
|
|
)
|
|
|
|
if not video_path:
|
|
return
|
|
|
|
srt_output_path = filedialog.asksaveasfilename(
|
|
title="Save SRT subtitles as...",
|
|
defaultextension=".srt",
|
|
filetypes=[("Subtitle files", "*.srt")]
|
|
)
|
|
|
|
if not srt_output_path:
|
|
return
|
|
|
|
progress_bar["value"] = 0
|
|
progress_label.config(text="Starting...")
|
|
root.update()
|
|
|
|
def update_progress(current, total):
|
|
percent = (current / total) * 100
|
|
progress_bar["value"] = percent
|
|
progress_label.config(text=f"Progress: {current}/{total} chunks")
|
|
root.update()
|
|
|
|
success = transcribe_video_to_srt(video_path, srt_output_path, progress_callback=update_progress)
|
|
|
|
if success:
|
|
messagebox.showinfo("Success", f"Subtitles saved to:\n{srt_output_path}")
|
|
else:
|
|
messagebox.showerror("Error", "Something went wrong. See console for details.")
|
|
|
|
progress_label.config(text="Done")
|
|
|
|
|
|
# GUI Setup
|
|
root = tk.Tk()
|
|
root.title("Auto Subtitle Generator (.srt) with Progress")
|
|
|
|
frame = tk.Frame(root, padx=20, pady=20)
|
|
frame.pack()
|
|
|
|
label = tk.Label(frame, text="Select a video file to auto-generate subtitles (SRT):")
|
|
label.pack(pady=(0, 10))
|
|
|
|
select_button = tk.Button(frame, text="Select Video and Generate Subtitles", command=select_file_and_generate)
|
|
select_button.pack(pady=5)
|
|
|
|
progress_bar = ttk.Progressbar(frame, length=300, mode="determinate")
|
|
progress_bar.pack(pady=(15, 5))
|
|
|
|
progress_label = tk.Label(frame, text="Idle")
|
|
progress_label.pack()
|
|
|
|
root.mainloop()
|