File size: 4,124 Bytes
29a56dd
 
 
7f71c49
29a56dd
7f71c49
 
 
 
 
29a56dd
 
7f71c49
 
 
d0d9535
29a56dd
d0d9535
7de3bfe
7f71c49
 
 
 
 
 
b70652d
7f71c49
29a56dd
7f71c49
29a56dd
7f71c49
29a56dd
7f71c49
 
 
 
29a56dd
 
 
 
7f71c49
29a56dd
7f71c49
29a56dd
 
 
 
7f71c49
29a56dd
 
 
 
7f71c49
 
29a56dd
 
 
 
 
 
 
de80961
29a56dd
7f71c49
de80961
 
7f71c49
29a56dd
7f71c49
29a56dd
7f71c49
 
29a56dd
 
 
 
 
 
 
 
 
 
 
 
 
7f71c49
 
 
29a56dd
 
 
7f71c49
 
 
29a56dd
 
 
 
 
 
 
de80961
29a56dd
 
 
 
de80961
29a56dd
7f71c49
29a56dd
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
"""
Streamlit File Extension Renamer
--------------------------------
Lightweight Streamlit app for Hugging Face Spaces.

Updates (2025‑05‑22):
* Ensures Streamlit has a writable config dir (`STREAMLIT_HOME`) inside container.
* Sets a fallback `HOME` env so `~/.streamlit` resolves safely.
* Compatible with Streamlit >=1.45.1 (bug‑fixed event‑loop).
"""
from __future__ import annotations

import os
import pathlib
import io
import zipfile
from datetime import datetime
from pathlib import Path

# ---------------------------------------------------------------------
# Environment hardening (MUST run before `import streamlit`)
# ---------------------------------------------------------------------
os.environ.setdefault("STREAMLIT_HOME", "/tmp/.streamlit")
os.environ.setdefault("HOME", "/tmp")
pathlib.Path(os.environ["STREAMLIT_HOME"]).mkdir(parents=True, exist_ok=True)

import streamlit as st

# ---------------------------------------------------------------------
# Configuration
# ---------------------------------------------------------------------
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",
]

DISALLOWED_SOURCE_EXTS: set[str] = {".exe", ".bin"}

# ---------------------------------------------------------------------
# UI helpers
# ---------------------------------------------------------------------

def make_sidebar() -> str:
    st.sidebar.header("Settings")
    target_ext = st.sidebar.selectbox(
        "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 file extensions. It does **not** "
        "convert the underlying format."
    )
    return target_ext


def make_uploader():
    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:
    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
# ---------------------------------------------------------------------

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 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 • Streamlit • Hugging Face Spaces")

if __name__ == "__main__":
    main()