import tkinter as tk from tkinter import scrolledtext from tkinterdnd2 import DND_FILES, TkinterDnD import re import os # --- Conversion Logic --- def convert_md_to_smf(markdown_text): """ Converts a Markdown string to an SMF-compatible BBCode string. The order of replacements is important to avoid conflicts. """ smf_text = markdown_text # 1. Block elements (Code blocks, blockquotes) # Code blocks (```...```) - DOTALL flag allows `.` to match newlines smf_text = re.sub(r'```(.*?)```', r'[code]\1[/code]', smf_text, flags=re.DOTALL) # Blockquotes (>) smf_text = re.sub(r'^\> (.*)', r'[quote]\1[/quote]', smf_text, flags=re.MULTILINE) # 2. Headings (must be at the start of a line) smf_text = re.sub(r'^# (.*)', r'[size=18pt][b]\1[/b][/size]', smf_text, flags=re.MULTILINE) smf_text = re.sub(r'^## (.*)', r'[size=16pt][b]\1[/b][/size]', smf_text, flags=re.MULTILINE) smf_text = re.sub(r'^### (.*)', r'[size=14pt][b]\1[/b][/size]', smf_text, flags=re.MULTILINE) smf_text = re.sub(r'^#### (.*)', r'[size=14pt][b]\1[/b][/size]', smf_text, flags=re.MULTILINE) # 3. Lists (must be at the start of a line) # This is a simplified conversion. It doesn't wrap the whole block in [list] tags, # as that requires more complex state management, but it's often sufficient. smf_text = re.sub(r'^\* (.*)', r'[li]\1[/li]', smf_text, flags=re.MULTILINE) smf_text = re.sub(r'^- (.*)', r'[li]\1[/li]', smf_text, flags=re.MULTILINE) smf_text = re.sub(r'^\d+\. (.*)', r'[li]\1[/li]', smf_text, flags=re.MULTILINE) # Note: SMF may need [list type=decimal] wrapper # 4. Images and Links smf_text = re.sub(r'!\[.*?\]\((.*?)\)', r'[img]\1[/img]', smf_text) # Images smf_text = re.sub(r'\[(.*?)\]\((.*?)\)', r'[url=\2]\1[/url]', smf_text) # Links # 5. Inline formatting smf_text = re.sub(r'\*\*(.*?)\*\*', r'[b]\1[/b]', smf_text) # Bold (**) smf_text = re.sub(r'__(.*?)__', r'[b]\1[/b]', smf_text) # Bold (__) smf_text = re.sub(r'\*(.*?)\*', r'[i]\1[/i]', smf_text) # Italic (*) smf_text = re.sub(r'_(.*?)_', r'[i]\1[/i]', smf_text) # Italic (_) smf_text = re.sub(r'~~(.*?)~~', r'[s]\1[/s]', smf_text) # Strikethrough smf_text = re.sub(r'`(.*?)`', r'[code]\1[/code]', smf_text) # Inline code # 6. Horizontal Rule smf_text = re.sub(r'^\s*---\s*$', '\n[hr]\n', smf_text, flags=re.MULTILINE) return smf_text # --- GUI Application --- class App(TkinterDnD.Tk): def __init__(self): super().__init__() self.title("Markdown to SMF Converter") self.geometry("500x400") # Main frame main_frame = tk.Frame(self) main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) # Label for instructions self.drop_label = tk.Label( main_frame, text="Drag and Drop .md files here", font=("Arial", 14), bg="lightblue", relief="solid", bd=2 ) self.drop_label.pack(fill=tk.BOTH, expand=True, pady=(0, 10)) # Scrolled text for status logs self.status_log = scrolledtext.ScrolledText( main_frame, height=10, state='disabled' # Make it read-only ) self.status_log.pack(fill=tk.BOTH, expand=True) # Register the drop zone self.drop_target_register(DND_FILES) self.dnd_bind('<>', self.handle_drop) self.log("Ready to convert files.") def log(self, message): """Adds a message to the status log.""" self.status_log.config(state='normal') self.status_log.insert(tk.END, message + "\n") self.status_log.see(tk.END) # Auto-scroll to the bottom self.status_log.config(state='disabled') def handle_drop(self, event): """Handles the file drop event.""" # The event.data is a string of file paths, sometimes in curly braces # We clean it up and split it into a list of individual paths file_paths = self.tk.splitlist(event.data) self.log("\n--- New Drop Detected ---") for file_path in file_paths: if file_path.lower().endswith('.md'): self.process_file(file_path) else: self.log(f"Skipped: '{os.path.basename(file_path)}' is not a .md file.") self.log("--- All files processed ---") def process_file(self, file_path): """Reads, converts, and saves a single markdown file.""" filename = os.path.basename(file_path) self.log(f"Processing: '{filename}'...") try: # Read the markdown file with open(file_path, 'r', encoding='utf-8') as f: markdown_content = f.read() # Convert the content smf_content = convert_md_to_smf(markdown_content) # Define the output path base_name = os.path.splitext(file_path)[0] output_path = f"{base_name}_smf.txt" # Save the converted content with open(output_path, 'w', encoding='utf-8') as f: f.write(smf_content) self.log(f"Success! Saved to: '{os.path.basename(output_path)}'") except Exception as e: self.log(f"Error processing '{filename}': {e}") # --- Main Execution --- if __name__ == "__main__": app = App() app.mainloop()