userIdc2024's picture
Update src/streamlit_app.py
337ef40 verified
import streamlit as st
import random
import tempfile
import os
import subprocess
from datetime import datetime
from dotenv import load_dotenv
load_dotenv()
# -----------------------------
# Device base definitions
# -----------------------------
BASE_MODELS = [
"iPhone 11", "iPhone 11 Pro", "iPhone 12", "iPhone 12 Pro",
"iPhone 13", "iPhone 13 Pro", "iPhone 13 Pro Max",
"iPhone 14", "iPhone 14 Pro", "iPhone 14 Pro Max",
"iPhone 15", "iPhone 15 Plus", "iPhone 15 Pro", "iPhone 15 Pro Max",
"iPhone 16", "iPhone 16 Pro", "iPhone 16 Pro Max"
]
IOS_VERSIONS = [f"iOS {v}" for v in range(14, 21)]
ISO_SPEEDS = [100, 200, 400, 800, 1600]
F_NUMBERS = ["f/1.3", "f/1.4", "f/1.5", "f/1.6", "f/1.8"]
FOCAL_LENGTHS = ["3.99 mm", "4.0 mm", "4.2 mm", "4.3 mm", "5.0 mm", "5.1 mm", "5.2 mm", "6.0 mm", "6.1 mm", "6.2 mm", "6.5 mm", "6.6 mm", "6.7 mm"]
EXPOSURES = ["1/60", "1/70", "1/100", "1/110", "1/120", "1/130", "1/140", "1/200", "1/220", "1/240", "1/300", "1/320", "1/400", "1/500", "1/600", "1/700", "1/1000"]
# -----------------------------
# Metadata generation
# -----------------------------
def generate_max_random_metadata():
"""Generate fully randomized video metadata simulating a random iPhone."""
model = random.choice(BASE_MODELS)
f_number = random.choice(F_NUMBERS)
focal_length = random.choice(FOCAL_LENGTHS)
exposure = random.choice(EXPOSURES)
iso_speed = random.choice(ISO_SPEEDS)
ios_version = random.choice(IOS_VERSIONS)
latitude = round(random.uniform(-90, 90), 6)
longitude = round(random.uniform(-180, 180), 6)
altitude = round(random.uniform(0, 100), 1)
camera_id = f"{model}-back-{random.randint(1000,9999)}"
metadata = {
"com.apple.quicktime.make": "Apple",
"com.apple.quicktime.model": model,
"com.apple.quicktime.software": ios_version,
"com.apple.quicktime.creationdate": datetime.now().strftime("%Y-%m-%dT%H:%M:%S"),
"com.apple.quicktime.location.name": "Random Location",
"com.apple.quicktime.location.ISO6709": f"{latitude}+{longitude}/",
"com.apple.quicktime.lensmodel": f"{model} {focal_length} {f_number}",
"com.apple.quicktime.make.identifier": "Apple iPhone Camera",
"com.apple.quicktime.camera.identifier": camera_id,
"com.apple.quicktime.exposuretime": exposure,
"com.apple.quicktime.fnumber": f_number,
"com.apple.quicktime.ISOSpeed": str(iso_speed),
"com.apple.quicktime.focallength": focal_length,
"com.apple.quicktime.gps.latitude": str(latitude),
"com.apple.quicktime.gps.longitude": str(longitude),
"com.apple.quicktime.gps.altitude": str(altitude)
}
return metadata
# -----------------------------
# Metadata update using FFmpeg
# -----------------------------
def update_video_metadata(video_bytes: bytes) -> tuple[bytes, dict]:
"""Apply maximal randomized metadata to a video."""
metadata = generate_max_random_metadata()
with tempfile.NamedTemporaryFile(delete=False, suffix=".mp4") as temp_in:
temp_in.write(video_bytes)
temp_in_path = temp_in.name
fd, temp_out_path = tempfile.mkstemp(suffix=".mp4")
os.close(fd)
metadata_args = []
for key, value in metadata.items():
safe_value = str(value).replace(":", "-") # basic sanitization
metadata_args.extend(["-metadata", f"{key}={safe_value}"])
cmd = [
"ffmpeg", "-y", "-i", temp_in_path,
*metadata_args,
"-movflags", "use_metadata_tags",
"-map_metadata", "0",
"-codec", "copy",
temp_out_path
]
process = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if process.returncode != 0:
os.remove(temp_in_path)
if os.path.exists(temp_out_path):
os.remove(temp_out_path)
raise RuntimeError(f"FFmpeg failed: {process.stderr.decode(errors='ignore')}")
with open(temp_out_path, "rb") as f:
updated_bytes = f.read()
os.remove(temp_in_path)
os.remove(temp_out_path)
return updated_bytes, metadata
# -----------------------------
# Streamlit UI
# -----------------------------
# -----------------------------
# Access Control
# -----------------------------
ACCESS_TOKEN = os.getenv("ACCESS_TOKEN") # Change this to your desired password
# Check if user is authenticated
if "authenticated" not in st.session_state:
st.session_state.authenticated = False
# Show login form if not authenticated
if not st.session_state.authenticated:
st.title("πŸ”’ Video Metadata Editor")
st.markdown("---")
# Input field for access token
user_input = st.text_input(
"Enter Access Token:",
type="password",
placeholder="Enter your access token"
)
# Login button
login_button = st.button("Login", type="primary")
if login_button:
if user_input == ACCESS_TOKEN:
st.session_state.authenticated = True
st.rerun()
else:
st.error("❌ Invalid access token. Please try again.")
st.stop()
# Main application (only shown if authenticated)
col1, col2 = st.columns([5, 1])
with col1:
st.title("Video Metadata Editor")
with col2:
if st.button("Logout", type="secondary"):
st.session_state.authenticated = False
st.rerun()
uploaded_video = st.file_uploader("Upload an MP4 video", type=["mp4"])
if uploaded_video is not None:
st.subheader("Original Video")
st.video(uploaded_video)
if st.button("Change Metadata"):
with st.spinner("Applying metadata..."):
try:
video_bytes = uploaded_video.read()
updated_video, metadata = update_video_metadata(video_bytes)
st.success(f"Metadata updated successfully!")
st.subheader("Updated Video")
st.video(updated_video)
st.download_button(
"Download Updated Video",
updated_video,
file_name="updated_metadata.mp4",
mime="video/mp4"
)
except Exception as e:
st.error(f"Error: {e}")