display / app.py
JAMESPARK3's picture
Update app.py
c5a30be verified
import streamlit as st
import os
import glob
import time
import base64
from streamlit.components.v1 import html
from streamlit_autorefresh import st_autorefresh
# ํŽ˜์ด์ง€ ์„ค์ •
st.set_page_config(
page_title="๋””์Šคํ”Œ๋ ˆ์ด ์ปจํ…์ธ  ๊ด€๋ฆฌ",
page_icon="๐Ÿ–ผ๏ธ",
layout="wide",
initial_sidebar_state="collapsed"
)
# ์ „์—ญ CSS ์„ค์ •
st.markdown("""
<style>
/* ์ „์ฒด ํ™”๋ฉด ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€ ์Šคํƒ€์ผ */
.full-view {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-position: center;
background-repeat: no-repeat;
background-color: black;
transition: opacity 1s ease-in-out;
z-index: 9998;
}
/* ์ปจํŠธ๋กค ํŒจ๋„ ์Šคํƒ€์ผ */
.controls-panel {
position: fixed;
bottom: 20px;
right: 20px;
z-index: 9999;
opacity: 0.2;
transition: opacity 0.3s;
}
.controls-panel:hover {
opacity: 1;
}
.view-toggle {
background-color: rgba(0, 0, 0, 0.5);
color: white;
border: none;
padding: 8px 16px;
margin: 5px;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
}
.view-toggle:hover {
background-color: rgba(0, 0, 0, 0.8);
}
/* ์• ๋‹ˆ๋ฉ”์ด์…˜ ํšจ๊ณผ */
.animate-fade {
animation: fadeIn 2s;
}
.animate-zoom {
animation: zoomIn 2s;
}
.animate-slide {
animation: slideIn 2s;
}
.animate-rotate {
animation: rotateIn 2s;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes zoomIn {
from { transform: scale(0.7); opacity: 0; }
to { transform: scale(1); opacity: 1; }
}
@keyframes slideIn {
from { transform: translateY(20%); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
@keyframes rotateIn {
from { transform: rotate(-10deg) scale(0.9); opacity: 0; }
to { transform: rotate(0) scale(1); opacity: 1; }
}
/* ์ด๋ฏธ์ง€ ๊ด€๋ฆฌ ๊ทธ๋ฆฌ๋“œ ์Šคํƒ€์ผ */
.image-item {
position: relative;
margin-bottom: 10px;
}
.image-item img {
width: 100%;
border-radius: 4px;
}
.image-actions {
position: absolute;
top: 5px;
right: 5px;
}
.image-name {
font-size: 12px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>
""", unsafe_allow_html=True)
# ์ „์ฒด ํ™”๋ฉด JS ํ•จ์ˆ˜
def inject_fullscreen_js():
js_code = """
<script>
function toggleFullScreen() {
var elem = document.documentElement;
if (!document.fullscreenElement && !document.mozFullScreenElement &&
!document.webkitFullscreenElement && !document.msFullscreenElement) {
if (elem.requestFullscreen) {
elem.requestFullscreen();
} else if (elem.msRequestFullscreen) {
elem.msRequestFullscreen();
} else if (elem.mozRequestFullScreen) {
elem.mozRequestFullScreen();
} else if (elem.webkitRequestFullscreen) {
elem.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
}
}
}
// ์ „์ฒด ํ™”๋ฉด ํ™œ์„ฑํ™” ์‹œ๋„
setTimeout(function() {
toggleFullScreen();
}, 1000);
</script>
"""
html(js_code, height=0, width=0)
# ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€ ํ‘œ์‹œ ๋ฐฉ์‹ ์ „ํ™˜์„ ์œ„ํ•œ JavaScript ํ•จ์ˆ˜
def inject_background_toggle_js():
js_code = """
<script>
// ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€ ํ‘œ์‹œ ๋ฐฉ์‹ ์ „ํ™˜ ํ•จ์ˆ˜
function toggleBackgroundFit() {
const fullView = document.querySelector('.full-view');
if (fullView) {
const currentFit = fullView.style.backgroundSize;
if (currentFit === 'cover') {
fullView.style.backgroundSize = 'contain';
document.getElementById('fit-toggle-btn').innerText = 'ํ™”๋ฉด์— ๊ฝ‰ ์ฐจ๊ฒŒ';
} else {
fullView.style.backgroundSize = 'cover';
document.getElementById('fit-toggle-btn').innerText = '์›๋ณธ ๋น„์œจ ์œ ์ง€';
}
}
}
// ์ „์—ญ ๋ฒ”์œ„์— ํ•จ์ˆ˜ ๋…ธ์ถœ (window ๊ฐ์ฒด์— ์ถ”๊ฐ€)
window.applyBackgroundAnimation = function(animationType) {
const fullView = document.querySelector('.full-view');
if (fullView) {
// ๋ชจ๋“  ์• ๋‹ˆ๋ฉ”์ด์…˜ ํด๋ž˜์Šค ์ œ๊ฑฐ
fullView.classList.remove('animate-fade', 'animate-zoom', 'animate-slide', 'animate-rotate');
// ์ƒˆ ์• ๋‹ˆ๋ฉ”์ด์…˜ ํด๋ž˜์Šค ์ถ”๊ฐ€
void fullView.offsetWidth; // ๊ฐ•์ œ ๋ฆฌํ”Œ๋กœ์šฐ
fullView.classList.add(animationType);
}
}
</script>
"""
html(js_code, height=0, width=0)
# URL ํŒŒ๋ผ๋ฏธํ„ฐ ์ฒ˜๋ฆฌ
try:
query_params = st.query_params
# ์ „์ฒดํ™”๋ฉด ๋ชจ๋“œ ํ™•์ธ
if "fullscreen" in query_params and query_params["fullscreen"][0].lower() == "true":
st.session_state.preview_mode = True
st.session_state.activate_fullscreen = True
# ์ด๋ฏธ์ง€ ์ „ํ™˜ ๋ชจ๋“œ ํ™•์ธ
if "change" in query_params:
st.session_state.fixed_image_enabled = False
# ๋‹จ์ผ ์ด๋ฏธ์ง€ ๋ชจ๋“œ ํ™•์ธ
elif "1image" in query_params: # change์™€ 1image ๋‘˜ ๋‹ค ์žˆ์œผ๋ฉด change๊ฐ€ ์šฐ์„ ํ•˜๋„๋ก elif ์‚ฌ์šฉ
st.session_state.fixed_image_enabled = True
# ํŠน์ • ์ด๋ฏธ์ง€ ์ธ๋ฑ์Šค๊ฐ€ ์ง€์ •๋˜์—ˆ๋Š”์ง€ ํ™•์ธ
if "image" in query_params:
try:
img_index = int(query_params["image"])
# contents ํด๋” ๋‚ด์˜ ๋ชจ๋“  ์ด๋ฏธ์ง€ ํŒŒ์ผ ๋ฏธ๋ฆฌ ๋กœ๋“œ
if not os.path.exists('contents'):
os.makedirs('contents')
image_files = glob.glob('contents/*.jpg') + glob.glob('contents/*.jpeg') + glob.glob('contents/*.png')
# ์ธ๋ฑ์Šค๊ฐ€ ์œ ํšจํ•œ์ง€ ํ™•์ธ
if 0 <= img_index < len(image_files):
st.session_state.fixed_image_path = image_files[img_index]
elif image_files: # ์œ ํšจํ•˜์ง€ ์•Š์ง€๋งŒ ์ด๋ฏธ์ง€๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€ ์‚ฌ์šฉ
st.session_state.fixed_image_path = image_files[0]
except ValueError:
# ์ˆซ์ž๋กœ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ
pass
except Exception as e:
st.error(f"URL ํŒŒ๋ผ๋ฏธํ„ฐ ์ฒ˜๋ฆฌ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {e}")
# ์ดˆ๊ธฐ ์„ค์ • ๋ฐ ์ƒํƒœ ๊ด€๋ฆฌ (๊ธฐ์กด ์ฝ”๋“œ ์ˆ˜์ •)
if 'contents' not in st.session_state:
# contents ํด๋” ๋‚ด์˜ ๋ชจ๋“  ์ด๋ฏธ์ง€ ํŒŒ์ผ ๋กœ๋“œ
if not os.path.exists('contents'):
os.makedirs('contents')
image_files = glob.glob('contents/*.jpg') + glob.glob('contents/*.jpeg') + glob.glob('contents/*.png')
st.session_state.contents = image_files
if 'current_image_index' not in st.session_state:
st.session_state.current_image_index = 0
if 'animation_type' not in st.session_state:
st.session_state.animation_type = 'animate-fade'
if 'activate_fullscreen' not in st.session_state:
st.session_state.activate_fullscreen = False
if 'fit_mode' not in st.session_state:
st.session_state.fit_mode = 'cover' # ๊ธฐ๋ณธ๊ฐ’์€ ํ™”๋ฉด์— ๊ฝ‰ ์ฐจ๊ฒŒ
if 'app_loaded' not in st.session_state:
st.session_state.app_loaded = False
# ๊ธฐ์กด ์ฝ”๋“œ๋ฅผ ์กฐ๊ฑด๋ถ€๋กœ ์ˆ˜์ •
if 'fixed_image_enabled' not in st.session_state:
st.session_state.fixed_image_enabled = False
if 'fixed_image_path' not in st.session_state and st.session_state.contents:
st.session_state.fixed_image_path = st.session_state.contents[0] if st.session_state.contents else None
# ์Šฌ๋ผ์ด๋“œ์‡ผ ์ž๋™ ์‹œ์ž‘ ๋กœ์ง
if not st.session_state.app_loaded and not st.session_state.get('preview_mode', False):
if st.session_state.contents and not st.session_state.fixed_image_enabled: # ์ด๋ฏธ์ง€๊ฐ€ ์žˆ๊ณ  ๊ณ ์ • ๋ชจ๋“œ๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ์—๋งŒ ์ž๋™ ์‹œ์ž‘
st.session_state.preview_mode = True
st.session_state.preview_start_time = time.time()
st.session_state.activate_fullscreen = True
st.session_state.app_loaded = True # ์•ฑ์ด ๋กœ๋“œ๋˜์—ˆ์Œ์„ ํ‘œ์‹œ
# ์‚ฌ์ด๋“œ๋ฐ” - ์ด๋ฏธ์ง€ ๊ด€๋ฆฌ
with st.sidebar:
st.title("๐Ÿ“ธ ๋””์Šคํ”Œ๋ ˆ์ด ์„ค์ •")
# ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ
st.subheader("์ด๋ฏธ์ง€ ์ถ”๊ฐ€")
uploaded_files = st.file_uploader("์ด๋ฏธ์ง€ ํŒŒ์ผ์„ ์—…๋กœ๋“œํ•˜์„ธ์š”", type=["jpg", "jpeg", "png"], accept_multiple_files=True)
if uploaded_files:
for uploaded_file in uploaded_files:
# contents ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ์—†์œผ๋ฉด ์ƒ์„ฑ
if not os.path.exists('contents'):
os.makedirs('contents')
# ์ €์žฅ ๊ฒฝ๋กœ ์ƒ์„ฑ
file_path = os.path.join('contents', uploaded_file.name)
# ์ด๋ฏธ์ง€ ์ €์žฅ
with open(file_path, "wb") as f:
f.write(uploaded_file.getvalue())
# ์ €์žฅ๋œ ์ด๋ฏธ์ง€๋ฅผ ๋ชฉ๋ก์— ์ถ”๊ฐ€ (์ค‘๋ณต ๋ฐฉ์ง€)
if file_path not in st.session_state.contents:
st.session_state.contents.append(file_path)
st.success(f"{len(uploaded_files)}๊ฐœ ์ด๋ฏธ์ง€๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.")
# ์ด๋ฏธ์ง€ ๋ชฉ๋ก ๋ฐ ๊ด€๋ฆฌ
st.subheader("์ด๋ฏธ์ง€ ์ˆœ์„œ ์กฐ์ •")
if not st.session_state.contents:
st.info("๋“ฑ๋ก๋œ ์ด๋ฏธ์ง€๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ด๋ฏธ์ง€๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ์„ธ์š”.")
else:
# ์ด๋ฏธ์ง€ ๋ชฉ๋ก ํ‘œ์‹œ ๋ฐ ์ˆœ์„œ ์กฐ์ •
for i, img_path in enumerate(st.session_state.contents):
col1, col2 = st.columns([3, 1])
with col1:
st.text(os.path.basename(img_path))
st.image(img_path, width=150)
with col2:
# ์œ„๋กœ ์ด๋™ ๋ฒ„ํŠผ
if i > 0 and st.button("๐Ÿ‘†", key=f"up_{i}"):
st.session_state.contents[i], st.session_state.contents[i-1] = st.session_state.contents[i-1], st.session_state.contents[i]
st.rerun()
# ์•„๋ž˜๋กœ ์ด๋™ ๋ฒ„ํŠผ
if i < len(st.session_state.contents) - 1 and st.button("๐Ÿ‘‡", key=f"down_{i}"):
st.session_state.contents[i], st.session_state.contents[i+1] = st.session_state.contents[i+1], st.session_state.contents[i]
st.rerun()
# ์‚ญ์ œ ๋ฒ„ํŠผ
if st.button("๐Ÿ—‘๏ธ", key=f"delete_{i}"):
del st.session_state.contents[i]
st.rerun()
st.markdown("<hr>", unsafe_allow_html=True)
# ์ด๋ฏธ์ง€ ๊ณ ์ • ์„ค์ •
st.subheader("์ด๋ฏธ์ง€ ๊ณ ์ • ์„ค์ •")
fixed_image_enabled = st.checkbox(
"ํ•œ ์ด๋ฏธ์ง€๋งŒ ๊ณ ์ •ํ•˜์—ฌ ํ‘œ์‹œ",
value=st.session_state.fixed_image_enabled,
help="์ฒดํฌํ•˜๋ฉด ์„ ํƒํ•œ ์ด๋ฏธ์ง€๋งŒ ๊ณ„์† ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ์Šฌ๋ผ์ด๋“œ์‡ผ๊ฐ€ ์ค‘์ง€๋ฉ๋‹ˆ๋‹ค."
)
# ์ฒดํฌ๋ฐ•์Šค ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋˜์—ˆ์„ ๋•Œ ์„ธ์…˜ ์ƒํƒœ ์—…๋ฐ์ดํŠธ
if fixed_image_enabled != st.session_state.fixed_image_enabled:
st.session_state.fixed_image_enabled = fixed_image_enabled
# ๊ณ ์ • ๋ชจ๋“œ๊ฐ€ ๋น„ํ™œ์„ฑํ™”๋˜๋ฉด ์Šฌ๋ผ์ด๋“œ์‡ผ ์žฌ๊ฐœ
if not fixed_image_enabled and st.session_state.get('preview_mode', False):
st.session_state.preview_start_time = time.time()
# ์ด๋ฏธ์ง€ ๊ณ ์ • ๋ชจ๋“œ๊ฐ€ ํ™œ์„ฑํ™”๋œ ๊ฒฝ์šฐ์—๋งŒ ์ด๋ฏธ์ง€ ์„ ํƒ ๋“œ๋กญ๋‹ค์šด ํ‘œ์‹œ
if st.session_state.fixed_image_enabled:
# ์ด๋ฏธ์ง€ ํŒŒ์ผ ๊ฒฝ๋กœ์—์„œ ํŒŒ์ผ๋ช…๋งŒ ์ถ”์ถœํ•˜์—ฌ ํ‘œ์‹œ ์˜ต์…˜ ์ƒ์„ฑ
image_options = {img_path: os.path.basename(img_path) for img_path in st.session_state.contents}
# ์„ ํƒ๋œ ์ด๋ฏธ์ง€๊ฐ€ ์—†๊ฑฐ๋‚˜ ๋ชฉ๋ก์— ์—†๋Š” ๊ฒฝ์šฐ ์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€ ์„ ํƒ
default_index = 0
if st.session_state.fixed_image_path in image_options:
default_index = list(image_options.keys()).index(st.session_state.fixed_image_path)
# ์ด๋ฏธ์ง€ ์„ ํƒ ๋“œ๋กญ๋‹ค์šด
if st.session_state.contents: # ์ด๋ฏธ์ง€๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ์—๋งŒ ๋“œ๋กญ๋‹ค์šด ํ‘œ์‹œ
selected_image = st.selectbox(
"๊ณ ์ •ํ•  ์ด๋ฏธ์ง€ ์„ ํƒ",
options=list(image_options.keys()),
format_func=lambda x: image_options[x],
index=default_index
)
# ์„ ํƒ๋œ ์ด๋ฏธ์ง€ ์ €์žฅ
st.session_state.fixed_image_path = selected_image
# ์„ ํƒ๋œ ์ด๋ฏธ์ง€ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ํ‘œ์‹œ
st.image(selected_image, caption="์„ ํƒ๋œ ์ด๋ฏธ์ง€", width=200)
else:
st.warning("ํ‘œ์‹œํ•  ์ด๋ฏธ์ง€๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ด๋ฏธ์ง€๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ์„ธ์š”.")
# ์• ๋‹ˆ๋ฉ”์ด์…˜ ํšจ๊ณผ ์„ ํƒ (๊ณ„์†)
animation_options = {
'animate-fade': 'ํŽ˜์ด๋“œ ์ธ/์•„์›ƒ',
'animate-zoom': '์คŒ ์ธ/์•„์›ƒ',
'animate-slide': '์Šฌ๋ผ์ด๋“œ',
'animate-rotate': 'ํšŒ์ „'
}
selected_animation = st.radio(
"์ „ํ™˜ ํšจ๊ณผ ์„ ํƒ",
options=list(animation_options.keys()),
format_func=lambda x: animation_options[x],
index=list(animation_options.keys()).index(st.session_state.animation_type) if st.session_state.animation_type in animation_options else 0
)
if selected_animation != st.session_state.animation_type:
st.session_state.animation_type = selected_animation
# ์žฌ์ƒ ์„ค์ •
st.subheader("์žฌ์ƒ ์„ค์ •")
# ์ด๋ฏธ์ง€ ํ‘œ์‹œ ๋ชจ๋“œ ์„ ํƒ
fit_options = {
'cover': 'ํ™”๋ฉด์— ๊ฝ‰ ์ฐจ๊ฒŒ',
'contain': '์›๋ณธ ๋น„์œจ ์œ ์ง€'
}
selected_fit = st.radio(
"์ด๋ฏธ์ง€ ํ‘œ์‹œ ๋ฐฉ์‹",
options=list(fit_options.keys()),
format_func=lambda x: fit_options[x],
index=list(fit_options.keys()).index(st.session_state.fit_mode) if st.session_state.fit_mode in fit_options else 0
)
if selected_fit != st.session_state.fit_mode:
st.session_state.fit_mode = selected_fit
# ์Šฌ๋ผ์ด๋“œ์‡ผ ๊ฐ„๊ฒฉ ์„ค์ •
preview_interval = st.slider("์ด๋ฏธ์ง€ ์ „ํ™˜ ๊ฐ„๊ฒฉ (์ดˆ)", min_value=1, max_value=60, value=10)
# ์Šฌ๋ผ์ด๋“œ์‡ผ ์‹œ์ž‘/์ข…๋ฃŒ ๋ฒ„ํŠผ
col1, col2 = st.columns(2)
with col1:
if st.button("๐Ÿ–ผ๏ธ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์‹œ์ž‘", use_container_width=True):
st.session_state.preview_mode = True
st.session_state.preview_start_time = time.time()
st.session_state.activate_fullscreen = False
st.rerun()
with col2:
if st.button("๐Ÿ” ์ „์ฒดํ™”๋ฉด ๋ณด๊ธฐ", use_container_width=True):
st.session_state.preview_mode = True
st.session_state.preview_start_time = time.time()
st.session_state.activate_fullscreen = True
st.rerun()
# ๋ฏธ๋ฆฌ๋ณด๊ธฐ ๋ชจ๋“œ์ธ ๊ฒฝ์šฐ ์ข…๋ฃŒ ๋ฒ„ํŠผ ํ‘œ์‹œ
if st.session_state.get('preview_mode', False):
if st.button("โน๏ธ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์ข…๋ฃŒ", use_container_width=True):
st.session_state.preview_mode = False
st.session_state.activate_fullscreen = False
st.rerun()
# ์‚ฌ์ด๋“œ๋ฐ” ํ•˜๋‹จ์— URL ์ •๋ณด ์ถ”๊ฐ€
st.sidebar.markdown("---")
st.sidebar.subheader("์ ‘์† URL")
base_url = "https://jamespark3-display.hf.space/"
# ์ด๋ฏธ์ง€ ์ „ํ™˜ ๋ชจ๋“œ URL
transition_url = f"{base_url}?fullscreen=true&change"
st.sidebar.text_area("์ด๋ฏธ์ง€ ์ „ํ™˜ ๋ชจ๋“œ", transition_url, help="์ด URL๋กœ ์ ‘์†ํ•˜๋ฉด ์ž๋™์œผ๋กœ ์ด๋ฏธ์ง€ ์ „ํ™˜ ๋ชจ๋“œ๋กœ ์‹œ์ž‘๋ฉ๋‹ˆ๋‹ค.")
# ๋‹จ์ผ ์ด๋ฏธ์ง€ ๋ชจ๋“œ URL
if st.session_state.fixed_image_enabled and st.session_state.fixed_image_path and st.session_state.contents:
current_img_index = st.session_state.contents.index(st.session_state.fixed_image_path) if st.session_state.fixed_image_path in st.session_state.contents else 0
single_url = f"{base_url}?fullscreen=true&1image&image={current_img_index}"
st.sidebar.text_area("ํ˜„์žฌ ์„ ํƒ๋œ ์ด๋ฏธ์ง€ ๋ชจ๋“œ", single_url, help="์ด URL๋กœ ์ ‘์†ํ•˜๋ฉด ์„ ํƒ๋œ ์ด๋ฏธ์ง€๋งŒ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.")
else:
single_url = f"{base_url}?fullscreen=true&1image"
st.sidebar.text_area("๋‹จ์ผ ์ด๋ฏธ์ง€ ๋ชจ๋“œ", single_url, help="์ด URL๋กœ ์ ‘์†ํ•˜๋ฉด ์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€๊ฐ€ ๊ณ ์ •๋˜์–ด ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.")
# ๋ฉ”์ธ ์ปจํ…์ธ  ์˜์—ญ
if st.session_state.get('preview_mode', False):
# ํ—ˆ๊น…ํŽ˜์ด์Šค UI ์š”์†Œ ์ˆจ๊ธฐ๊ธฐ ์œ„ํ•œ CSS ์ถ”๊ฐ€
st.markdown("""
<style>
/* ํ—ˆ๊น…ํŽ˜์ด์Šค ํ—ค๋” ๋ฐ ๊ด€๋ จ UI ์š”์†Œ ์ˆจ๊ธฐ๊ธฐ */
div.css-1avcm0n {display: none !important;} /* ์ƒ๋‹จ ํ—ค๋” */
div.css-14xtw13 {display: none !important;} /* ๊ณต๊ฐ„ */
section.css-1lcbmhc {display: none !important;} /* ์‚ฌ์ด๋“œ๋ฐ” */
div.css-1dp5vir {display: none !important;} /* ๊ธฐํƒ€ UI ์š”์†Œ */
div.e1nzilvr5 {display: none !important;}
div.viewerBadge_link__1S137 {display: none !important;}
div.css-1bgch32 {display: none !important;}
/* Streamlit ์š”์†Œ ์ˆจ๊ธฐ๊ธฐ */
#MainMenu {visibility: hidden !important;}
header {visibility: hidden !important;}
footer {visibility: hidden !important;}
/* iframe ๊ด€๋ จ ์„ค์ • */
iframe {border: none !important;}
/* ์•ฑ ์ปจํ…Œ์ด๋„ˆ ์ „์ฒด ํ™”๋ฉด ์„ค์ • */
.main .block-container {
padding: 0 !important;
max-width: 100% !important;
}
.stApp {
margin: 0 !important;
padding: 0 !important;
height: 100vh !important;
width: 100vw !important;
overflow: hidden !important;
}
/* ์ „์ฒด ํ™”๋ฉด ์„ค์ • ๊ฐ•ํ™” */
body {
margin: 0 !important;
padding: 0 !important;
overflow: hidden !important;
}
/* ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€ ์ปจํ…Œ์ด๋„ˆ ์ˆ˜์ • */
.full-view {
position: fixed !important;
top: 0 !important;
left: 0 !important;
width: 100vw !important;
height: 100vh !important;
z-index: 9999 !important;
}
</style>
""", unsafe_allow_html=True)
# ์ž๋™ ์ƒˆ๋กœ๊ณ ์นจ์„ ์œ„ํ•œ ์นด์šดํ„ฐ
count = st_autorefresh(interval=preview_interval * 1000, key="refreshInterval")
# ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€ ์ „ํ™˜ JS ์‚ฝ์ž… (๋จผ์ € ์‹คํ–‰๋˜์–ด์•ผ ํ•จ)
inject_background_toggle_js()
# ์ „์ฒดํ™”๋ฉด ํ™œ์„ฑํ™” ํ•„์š”์‹œ ์‹คํ–‰
if st.session_state.activate_fullscreen:
inject_fullscreen_js()
# ํ˜„์žฌ ์ธ๋ฑ์Šค ์—…๋ฐ์ดํŠธ
if count > 0 and st.session_state.contents:
# ์ด๋ฏธ์ง€ ๊ณ ์ • ๋ชจ๋“œ๊ฐ€ ํ™œ์„ฑํ™”๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ์—๋งŒ ์ด๋ฏธ์ง€ ๋ณ€๊ฒฝ
if not st.session_state.fixed_image_enabled:
st.session_state.current_image_index = (st.session_state.current_image_index + 1) % len(st.session_state.contents)
# ํ™”๋ฉด์— ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€๋กœ ํ‘œ์‹œ
if st.session_state.contents:
# ์ด๋ฏธ์ง€ ๊ณ ์ • ๋ชจ๋“œ๊ฐ€ ํ™œ์„ฑํ™”๋œ ๊ฒฝ์šฐ ๊ณ ์ • ์ด๋ฏธ์ง€ ์‚ฌ์šฉ, ์•„๋‹ˆ๋ฉด ํ˜„์žฌ ์ธ๋ฑ์Šค ์ด๋ฏธ์ง€ ์‚ฌ์šฉ
if st.session_state.fixed_image_enabled and st.session_state.fixed_image_path:
full_img_path = st.session_state.fixed_image_path
else:
full_img_path = st.session_state.contents[st.session_state.current_image_index]
# ์›น์—์„œ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ์ด๋ฏธ์ง€ URL๋กœ ๋ณ€ํ™˜ (Base64 ์ธ์ฝ”๋”ฉ ์‚ฌ์šฉ)
with open(full_img_path, "rb") as img_file:
img_data = base64.b64encode(img_file.read()).decode()
# ์ด๋ฏธ์ง€ ํ™•์žฅ์ž ๊ฐ€์ ธ์˜ค๊ธฐ (๊ธฐ๋ณธ๊ฐ’์€ jpeg)
file_ext = os.path.splitext(full_img_path)[1][1:] or "jpeg"
# ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€ ์„ค์ •๊ณผ ์ปจํŠธ๋กค ๋ฒ„ํŠผ์ด ํฌํ•จ๋œ HTML ์ƒ์„ฑ
background_html = f"""
<div class="full-view animate-{st.session_state.animation_type}"
style="background-image: url('data:image/{file_ext};base64,{img_data}');
background-size: {st.session_state.fit_mode};">
<div class="controls-panel">
<button id="fit-toggle-btn" class="view-toggle" onclick="toggleBackgroundFit()">
{'์›๋ณธ ๋น„์œจ ์œ ์ง€' if st.session_state.fit_mode == 'cover' else 'ํ™”๋ฉด์— ๊ฝ‰ ์ฐจ๊ฒŒ'}
</button>
<button id="exit-btn" class="view-toggle" onclick="window.location.href=window.location.pathname">
๋ฏธ๋ฆฌ๋ณด๊ธฐ ์ข…๋ฃŒ
</button>
</div>
</div>
<script>
// ์ „์ฒดํ™”๋ฉด ํ™œ์„ฑํ™”
setTimeout(function() {{
var elem = document.documentElement;
if (elem.requestFullscreen) {{
elem.requestFullscreen();
}} else if (elem.mozRequestFullScreen) {{
elem.mozRequestFullScreen();
}} else if (elem.webkitRequestFullscreen) {{
elem.webkitRequestFullscreen();
}} else if (elem.msRequestFullscreen) {{
elem.msRequestFullscreen();
}}
}}, 1000);
// ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ ์šฉ (window ๊ฐ์ฒด์—์„œ ํ•จ์ˆ˜ ํ˜ธ์ถœ)
setTimeout(function() {{
if (typeof window.applyBackgroundAnimation === 'function') {{
window.applyBackgroundAnimation('animate-{st.session_state.animation_type}');
}}
}}, 1500);
// ํ—ˆ๊น…ํŽ˜์ด์Šค ์š”์†Œ ์ˆจ๊ธฐ๊ธฐ ๊ฐ•ํ™”
function hideHuggingfaceElements() {{
const huggingfaceElements = document.querySelectorAll('.css-1avcm0n, .css-14xtw13, .css-1lcbmhc, .css-1dp5vir, .e1nzilvr5, .viewerBadge_link__1S137, .css-1bgch32');
huggingfaceElements.forEach(el => {{
if(el) el.style.display = 'none';
}});
}}
// ์—ฌ๋Ÿฌ ๋ฒˆ ์‹œ๋„ํ•˜์—ฌ UI ์š”์†Œ ์ˆจ๊ธฐ๊ธฐ
setTimeout(hideHuggingfaceElements, 1000);
setTimeout(hideHuggingfaceElements, 2000);
setTimeout(hideHuggingfaceElements, 5000);
</script>
"""
# HTML ์ง์ ‘ ์‚ฝ์ž…
st.markdown(background_html, unsafe_allow_html=True)
# Streamlit ์š”์†Œ ์ˆจ๊ธฐ๊ธฐ
st.markdown("""
<style>
#MainMenu {visibility: hidden;}
header {visibility: hidden;}
footer {visibility: hidden;}
</style>
""", unsafe_allow_html=True)
else:
# ์ผ๋ฐ˜ ๋ชจ๋“œ - ์•ฑ ์†Œ๊ฐœ ๋ฐ ์‚ฌ์šฉ๋ฒ•
st.title("๐Ÿ–ผ๏ธ ๋””์ง€ํ„ธ ๋””์Šคํ”Œ๋ ˆ์ด ์ปจํ…์ธ  ๊ด€๋ฆฌ")
if not st.session_state.contents:
st.warning("โš ๏ธ ๋“ฑ๋ก๋œ ์ด๋ฏธ์ง€๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์‚ฌ์ด๋“œ๋ฐ”์—์„œ ์ด๋ฏธ์ง€๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ์„ธ์š”.")
else:
st.success(f"โœ… {len(st.session_state.contents)}๊ฐœ์˜ ์ด๋ฏธ์ง€๊ฐ€ ๋“ฑ๋ก๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.")
st.markdown("""
### ์‚ฌ์šฉ ๋ฐฉ๋ฒ•
1. ์™ผ์ชฝ ์‚ฌ์ด๋“œ๋ฐ”์—์„œ ์ด๋ฏธ์ง€๋ฅผ ์ถ”๊ฐ€ํ•˜์„ธ์š”.
2. ์ด๋ฏธ์ง€ ์ˆœ์„œ๋ฅผ ์กฐ์ •ํ•˜๊ณ  ์ „ํ™˜ ํšจ๊ณผ๋ฅผ ์„ ํƒํ•˜์„ธ์š”.
3. ์žฌ์ƒ ์„ค์ •์—์„œ ์ด๋ฏธ์ง€ ํ‘œ์‹œ ๋ฐฉ์‹๊ณผ ์ „ํ™˜ ๊ฐ„๊ฒฉ์„ ์„ค์ •ํ•˜์„ธ์š”.
4. ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์‹œ์ž‘ ๋˜๋Š” ์ „์ฒดํ™”๋ฉด ๋ณด๊ธฐ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜์—ฌ ์Šฌ๋ผ์ด๋“œ์‡ผ๋ฅผ ์‹œ์ž‘ํ•˜์„ธ์š”.
### ๊ธฐ๋Šฅ ์†Œ๊ฐœ
- **์ด๋ฏธ์ง€ ์ˆœ์„œ ์กฐ์ •**: ๐Ÿ‘†๐Ÿ‘‡ ๋ฒ„ํŠผ์œผ๋กœ ์ด๋ฏธ์ง€ ์ˆœ์„œ๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
- **์ด๋ฏธ์ง€ ๊ณ ์ •**: ํŠน์ • ์ด๋ฏธ์ง€ ํ•˜๋‚˜๋งŒ ๊ณ„์† ํ‘œ์‹œํ•˜๋„๋ก ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
- **์ „ํ™˜ ํšจ๊ณผ**: ํŽ˜์ด๋“œ, ์คŒ, ์Šฌ๋ผ์ด๋“œ, ํšŒ์ „ ํšจ๊ณผ๋ฅผ ์„ ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
- **ํ‘œ์‹œ ๋ฐฉ์‹**: ํ™”๋ฉด์— ๊ฝ‰ ์ฐจ๊ฒŒ ๋˜๋Š” ์›๋ณธ ๋น„์œจ์„ ์œ ์ง€ํ•˜๋ฉฐ ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
- **์ž๋™ ์ „ํ™˜**: ์„ค์ •ํ•œ ๊ฐ„๊ฒฉ์œผ๋กœ ์ด๋ฏธ์ง€๊ฐ€ ์ž๋™ ์ „ํ™˜๋ฉ๋‹ˆ๋‹ค.
### ์ด๋ฏธ์ง€ ๋ฏธ๋ฆฌ๋ณด๊ธฐ
""")
# ์ด๋ฏธ์ง€ ๊ทธ๋ฆฌ๋“œ๋กœ ํ‘œ์‹œ
if st.session_state.contents:
cols = st.columns(4)
for i, img_path in enumerate(st.session_state.contents):
with cols[i % 4]:
# use_column_width=True๋ฅผ use_container_width=True๋กœ ๋ณ€๊ฒฝ
st.image(img_path, caption=os.path.basename(img_path), use_container_width=True)