Spaces:
Running
Running
""" | |
Streamlit File Extension Renamer | |
-------------------------------- | |
A lightweight Streamlit app intended for deployment on Hugging Face Spaces. | |
The app lets users upload one or more files and rename (not convert) their | |
extensions to any common file-type extension the user selects. Executable | |
and binary files are blocked for security reasons. | |
""" | |
from __future__ import annotations | |
import os, pathlib | |
# 1️⃣ give Streamlit a real home BEFORE importing it | |
os.environ.setdefault("STREAMLIT_HOME", "/tmp/.streamlit") | |
pathlib.Path(os.environ["STREAMLIT_HOME"]).mkdir(parents=True, exist_ok=True) | |
import streamlit as st | |
import zipfile | |
from datetime import datetime | |
from pathlib import Path | |
# ----------------------------------------------------------------------------- | |
# Configuration | |
# ----------------------------------------------------------------------------- | |
# List of target extensions displayed to the user. Extend this list as needed. | |
ALLOWED_TARGET_EXTS: list[str] = [ | |
".txt", | |
".pdf", | |
".doc", | |
".docx", | |
".json", | |
".csv", | |
".xml", | |
".html", | |
".css", | |
".js", | |
".md", | |
".jpg", | |
".jpeg", | |
".png", | |
".gif", | |
".bmp", | |
".tiff", | |
".svg", | |
".ico", | |
".mp3", | |
".wav", | |
".mp4", | |
".avi", | |
".mkv", | |
".mov", | |
".zip", | |
".tar", | |
".gz", | |
".7z", | |
] | |
# Source‐file extensions that are disallowed (will be skipped if uploaded). | |
DISALLOWED_SOURCE_EXTS: set[str] = {".exe", ".bin"} | |
# ----------------------------------------------------------------------------- | |
# UI helpers | |
# ----------------------------------------------------------------------------- | |
def make_sidebar() -> str: | |
"""Return the user-chosen target extension from sidebar controls.""" | |
st.sidebar.header("Settings") | |
target_ext = st.sidebar.selectbox( | |
label="Target extension (applied to **all** uploaded files)", | |
options=ALLOWED_TARGET_EXTS, | |
index=ALLOWED_TARGET_EXTS.index(".pdf"), | |
) | |
st.sidebar.markdown( | |
"""❗ **Note**: This tool only renames the file extension. It does **not** | |
convert the underlying file format. Opening a renamed file with an | |
incompatible program may fail or lead to data corruption.""" | |
) | |
return target_ext | |
def make_uploader(): | |
"""Return the list of files uploaded by the user.""" | |
return st.file_uploader( | |
"Upload one or more files", | |
accept_multiple_files=True, | |
type=[ext.lstrip(".") for ext in ALLOWED_TARGET_EXTS], | |
help="Drag-and-drop or browse for files to rename.", | |
) | |
# ----------------------------------------------------------------------------- | |
# Core logic | |
# ----------------------------------------------------------------------------- | |
def write_zip(uploaded_files: list[st.runtime.uploaded_file_manager.UploadedFile], target_ext: str) -> io.BytesIO: | |
"""Return an in-memory ZIP archive of the uploaded files with the new extension.""" | |
buffer = io.BytesIO() | |
with zipfile.ZipFile(buffer, "w", zipfile.ZIP_DEFLATED) as zf: | |
for file in uploaded_files: | |
orig_path = Path(file.name) | |
if orig_path.suffix.lower() in DISALLOWED_SOURCE_EXTS: | |
st.warning(f"⏭️ Skipping disallowed file: **{orig_path.name}**") | |
continue | |
renamed = orig_path.with_suffix(target_ext) | |
zf.writestr(renamed.name, file.read()) | |
st.success(f"✅ Renamed **{orig_path.name}** → **{renamed.name}**") | |
buffer.seek(0) | |
return buffer | |
# ----------------------------------------------------------------------------- | |
# Main app | |
# ----------------------------------------------------------------------------- | |
def main() -> None: | |
st.set_page_config("Extension Renamer", page_icon="📄", layout="centered") | |
st.title("📄 Universal File-Extension Renamer") | |
st.write( | |
"Upload files, choose a new extension, and download them renamed in a single ZIP archive." | |
) | |
target_ext = make_sidebar() | |
uploaded_files = make_uploader() | |
if uploaded_files and st.button("🔄 Rename & Package"): | |
zip_buffer = write_zip(uploaded_files, target_ext) | |
timestamp = datetime.utcnow().strftime("%Y%m%dT%H%M%SZ") | |
st.download_button( | |
label="⬇️ Download ZIP", | |
data=zip_buffer, | |
file_name=f"renamed_{timestamp}.zip", | |
mime="application/zip", | |
) | |
st.caption("© 2025 File-Extension Renamer • Built with Streamlit • Deployed on Hugging Face Spaces") | |
if __name__ == "__main__": | |
main() | |