GameConfigIdea / file_explorer_and_upload.py
kwabs22
Port changes from duplicate space to original
9328e91
import os
import gradio as gr
import shutil
from PIL import Image
import tempfile
import json
import zipfile
# Set the directory where files will be saved
SAVE_DIR = os.path.abspath("saved_media") #make sure its the as media_folder Above
# Ensure the save directory exists
os.makedirs(SAVE_DIR, exist_ok=True)
# Define supported file extensions
SUPPORTED_EXTENSIONS = {
"image": [".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp"],
"audio": [".mp3", ".wav", ".ogg"],
"video": [".mp4", ".avi", ".mov", ".webm"],
"model3d": [".glb", ".gltf", ".obj"]
}
def save_file(file):
if file is None:
return "No file uploaded.", gr.update()
try:
# Get the original filename and extension
original_filename = os.path.basename(file.name)
_, extension = os.path.splitext(original_filename)
# Check if the file extension is supported
if not any(extension.lower() in exts for exts in SUPPORTED_EXTENSIONS.values()):
return f"Unsupported file type: {extension}", gr.update()
# Create a unique filename to avoid overwriting
base_name = os.path.splitext(original_filename)[0]
counter = 1
new_filename = f"{base_name}{extension}"
while os.path.exists(os.path.join(SAVE_DIR, new_filename)):
new_filename = f"{base_name}_{counter}{extension}"
counter += 1
# Copy the file from the temporary location to our save directory
dest_path = os.path.join(SAVE_DIR, new_filename)
shutil.copy2(file.name, dest_path)
# Return success message and updated FileExplorer
return f"File saved as {SAVE_DIR}/{new_filename}", gr.update(value=SAVE_DIR), gr.update(value=None)
except Exception as e:
return f"Error saving file: {str(e)}", gr.update(value=SAVE_DIR), gr.update()
def view_file(file_path):
"""View a file and return appropriate outputs for each media type.
Returns: (image, audio, video, message, model3d)
"""
if not file_path:
return None, None, None, "No file selected.", None
try:
# FileExplorer returns relative path from root_dir, or could be full path
# Handle both cases
if os.path.isabs(file_path):
full_path = file_path
elif file_path.startswith(SAVE_DIR):
full_path = file_path
else:
full_path = os.path.join(SAVE_DIR, file_path)
# Normalize the path
full_path = os.path.normpath(full_path)
if not os.path.exists(full_path):
return None, None, None, f"File not found: {full_path}", None
_, extension = os.path.splitext(full_path)
extension = extension.lower()
if extension in SUPPORTED_EXTENSIONS["image"]:
return Image.open(full_path), None, None, f"Viewing: {os.path.basename(full_path)}", None
elif extension in SUPPORTED_EXTENSIONS["audio"]:
return None, full_path, None, f"Viewing: {os.path.basename(full_path)}", None
elif extension in SUPPORTED_EXTENSIONS["video"]:
return None, None, full_path, f"Viewing: {os.path.basename(full_path)}", None
elif extension in SUPPORTED_EXTENSIONS["model3d"]:
return None, None, None, f"Viewing 3D: {os.path.basename(full_path)}", full_path
else:
return None, None, None, f"Unsupported file type: {extension}", None
except Exception as e:
return None, None, None, f"Error viewing file: {str(e)}", None
def get_all_media_files():
"""Get all media files from saved_media folder for use in dropdowns"""
try:
if not os.path.exists(SAVE_DIR):
return []
files = os.listdir(SAVE_DIR)
# Filter to only supported media files
media_files = []
for f in files:
ext = os.path.splitext(f)[1].lower()
if any(ext in exts for exts in SUPPORTED_EXTENSIONS.values()):
media_files.append(f)
return sorted(media_files)
except Exception as e:
print(f"Error listing media files: {e}")
return []
def refresh_file_explorer():
files = os.listdir(SAVE_DIR)
return gr.update(value=files)
def delete_file(file_path):
if os.path.exists(file_path):
os.remove(file_path)
fileexplorerupdate = refresh_file_explorer()
return fileexplorerupdate, f"{file_path} has been deleted."
else:
return f"{file_path} does not exist."
def delete_file_and_refresh(filename):
"""Delete file and return updated dropdown choices"""
if not filename:
return gr.update(choices=get_all_media_files()), "No file selected"
full_path = os.path.join(SAVE_DIR, filename)
if os.path.exists(full_path):
os.remove(full_path)
return gr.update(choices=get_all_media_files(), value=None), f"Deleted: {filename}"
return gr.update(choices=get_all_media_files()), f"File not found: {filename}"
def save_file_and_refresh(file):
"""Save file and return updated dropdown choices for Browse tab"""
if file is None:
return "No file uploaded.", gr.update(), gr.update(value=None)
try:
original_filename = os.path.basename(file.name)
_, extension = os.path.splitext(original_filename)
if not any(extension.lower() in exts for exts in SUPPORTED_EXTENSIONS.values()):
return f"Unsupported file type: {extension}", gr.update(), gr.update()
base_name = os.path.splitext(original_filename)[0]
counter = 1
new_filename = f"{base_name}{extension}"
while os.path.exists(os.path.join(SAVE_DIR, new_filename)):
new_filename = f"{base_name}_{counter}{extension}"
counter += 1
dest_path = os.path.join(SAVE_DIR, new_filename)
shutil.copy2(file.name, dest_path)
# Return updated dropdown choices
return f"File saved: {new_filename}", gr.update(choices=get_all_media_files()), gr.update(value=None)
except Exception as e:
return f"Error saving file: {str(e)}", gr.update(), gr.update()
def upload_file_or_bundle(file):
"""
Unified upload handler that handles both media files and zip bundles.
Returns: (status, dropdown_update, file_input_clear, config_json, extracted_files)
"""
if file is None:
return "No file uploaded.", gr.update(), gr.update(value=None), None, ""
try:
original_filename = os.path.basename(file.name)
_, extension = os.path.splitext(original_filename)
ext_lower = extension.lower()
# Check if it's a zip bundle
if ext_lower == ".zip":
try:
config, extracted_files = import_config_with_media(file.name)
config_json = json.dumps(config, indent=2)
files_str = "\n".join(extracted_files) if extracted_files else "No new files extracted (all already existed)"
status = f"Bundle imported! Config loaded, {len(extracted_files)} new media files extracted."
return (
status,
gr.update(choices=get_all_media_files()),
gr.update(value=None),
config_json,
files_str
)
except FileNotFoundError as e:
return f"Error: {str(e)}", gr.update(), gr.update(), None, ""
except Exception as e:
return f"Error importing bundle: {str(e)}", gr.update(), gr.update(), None, ""
# Handle regular media files
if not any(ext_lower in exts for exts in SUPPORTED_EXTENSIONS.values()):
return f"Unsupported file type: {extension}", gr.update(), gr.update(), None, ""
base_name = os.path.splitext(original_filename)[0]
counter = 1
new_filename = f"{base_name}{extension}"
while os.path.exists(os.path.join(SAVE_DIR, new_filename)):
new_filename = f"{base_name}_{counter}{extension}"
counter += 1
dest_path = os.path.join(SAVE_DIR, new_filename)
shutil.copy2(file.name, dest_path)
return (
f"File saved: {new_filename}",
gr.update(choices=get_all_media_files()),
gr.update(value=None),
None,
""
)
except Exception as e:
return f"Error: {str(e)}", gr.update(), gr.update(), None, ""
def export_config_with_media_wrapper(config_json):
"""Wrapper for export that provides status message along with the file"""
from my_text_game_engine_attempt import export_config_with_media
if not config_json or not config_json.strip():
return None, "Please paste a config JSON to export"
try:
zip_path = export_config_with_media(config_json)
return zip_path, f"Export successful! Bundle ready for download."
except json.JSONDecodeError as e:
return None, f"Invalid JSON: {str(e)}"
except Exception as e:
return None, f"Export failed: {str(e)}"
def import_config_with_media(zip_path):
global SAVE_DIR
target_folder = SAVE_DIR
"""
Import the config JSON and media files from a zip file.
Extract only the media files that don't already exist in the target folder.
:param zip_path: Path to the zip file containing the config and media files
:param target_folder: Path to the folder where media files should be extracted
:return: Tuple containing the loaded config (as a dictionary) and a list of newly extracted files
"""
config = None
extracted_files = []
with tempfile.TemporaryDirectory() as temp_dir:
# Extract all files to a temporary directory
with zipfile.ZipFile(zip_path, 'r') as zip_ref:
zip_ref.extractall(temp_dir)
# Load the config (check both config.json and game_config.json for compatibility)
config_path = os.path.join(temp_dir, 'config.json')
alt_config_path = os.path.join(temp_dir, 'game_config.json')
if os.path.exists(config_path):
with open(config_path, 'r') as f:
config = json.load(f)
elif os.path.exists(alt_config_path):
with open(alt_config_path, 'r') as f:
config = json.load(f)
else:
raise FileNotFoundError("config.json (or game_config.json) not found in the zip file")
# Create the target folder if it doesn't exist
os.makedirs(target_folder, exist_ok=True)
# Copy media files that don't already exist in the target folder
config_files = {'config.json', 'game_config.json'}
for root, _, files in os.walk(temp_dir):
for file in files:
if file not in config_files:
src_path = os.path.join(root, file)
dst_path = os.path.join(target_folder, file)
if not os.path.exists(dst_path):
shutil.copy2(src_path, dst_path)
extracted_files.append(file)
return config, extracted_files