Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -134,13 +134,9 @@ def html(cards, pg, total):
|
|
134 |
.hdr{padding:20px 24px;background:rgba(255,255,255,.75);backdrop-filter:blur(8px);border-bottom:1px solid #eee;}
|
135 |
.ttl{margin:0;font-size:1.15rem;font-weight:700;color:#333;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
|
136 |
.date{margin-top:4px;font-size:.85rem;color:#777;}
|
137 |
-
.frame{position:relative;width:100%;padding-top:60%;overflow:hidden;}
|
138 |
.frame iframe{position:absolute;top:0;left:0;width:142.857%;height:142.857%;
|
139 |
transform:scale(.7);transform-origin:top left;border:0;opacity:0;transition:opacity 0.3s;}
|
140 |
-
.foot{padding:14px 24px;background:rgba(255,255,255,.85);backdrop-filter:blur(8px);text-align:right;}
|
141 |
-
.link{font-size:.85rem;font-weight:600;color:#4a6dd8;text-decoration:none;}
|
142 |
-
.cnt{text-align:center;font-size:.85rem;color:#555;margin:10px 0 40px;}
|
143 |
-
/* ์ถ๊ฐ - iframe ์ค๋ฅ ์ํ ์ฒ๋ฆฌ */
|
144 |
.frame-error {position:absolute;top:0;left:0;width:100%;height:100%;
|
145 |
display:flex;align-items:center;justify-content:center;
|
146 |
background:#f8f8f8;color:#666;font-size:14px;text-align:center;
|
@@ -150,116 +146,73 @@ def html(cards, pg, total):
|
|
150 |
border-radius:20px;font-size:12px;cursor:pointer;border:none;
|
151 |
transition:all 0.2s ease;}
|
152 |
.frame-error-btn:hover {background:#3a5dc8;transform:scale(1.05);}
|
|
|
|
|
|
|
153 |
</style>
|
154 |
|
155 |
<script>
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
bypassUrl = bypassUrl + (hasQuery ? '&' : '?') + 'bypass=' + encodeURIComponent(BYPASS_SECRET);
|
170 |
}
|
171 |
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
// CORS ์ค๋ฅ ํ์ง ์๋
|
184 |
-
if(iframe.contentWindow.location.href) {
|
185 |
-
iframe.style.opacity = 1;
|
186 |
}
|
187 |
-
} catch (e) {
|
188 |
-
// CORS ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ฉด handleIframeError ํธ์ถ
|
189 |
-
console.log("CORS ์ค๋ฅ ๋๋ ๋ณดํธ๋ ๋ฐฐํฌ:", e);
|
190 |
-
handleIframeError(iframe);
|
191 |
}
|
192 |
-
|
193 |
-
|
194 |
-
// iframe ๋ก๋ ์ํ ํ์ธ
|
195 |
-
document.addEventListener('DOMContentLoaded', function() {
|
196 |
-
// ์๋ํ ์ฐํ ๋น๋ฐํค๊ฐ ์์ผ๋ฉด ์ ์ญ ๋ณ์๋ก ์ค์
|
197 |
-
const bypassSecret = "BYPASS_SECRET_PLACEHOLDER";
|
198 |
-
if (bypassSecret && bypassSecret !== "BYPASS_SECRET_PLACEHOLDER") {
|
199 |
-
window.BYPASS_SECRET = bypassSecret;
|
200 |
-
}
|
201 |
-
|
202 |
-
// ๋ชจ๋ iframe์ ํธ๋ค๋ฌ ์ถ๊ฐ
|
203 |
const frames = document.querySelectorAll('iframe');
|
204 |
frames.forEach(frame => {
|
205 |
-
//
|
206 |
-
|
207 |
-
let url = frame.src;
|
208 |
-
const hasQuery = url.includes('?');
|
209 |
-
url = url + (hasQuery ? '&' : '?') + 'bypass=' + encodeURIComponent(window.BYPASS_SECRET);
|
210 |
-
frame.src = url;
|
211 |
-
}
|
212 |
-
|
213 |
-
// ์ด๋ฒคํธ ๋ฆฌ์ค๋ ์ถ๊ฐ
|
214 |
-
frame.addEventListener('error', function() {
|
215 |
-
handleIframeError(this);
|
216 |
-
});
|
217 |
|
|
|
218 |
frame.addEventListener('load', function() {
|
219 |
handleIframeLoad(this);
|
220 |
});
|
221 |
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
handleIframeError(frame);
|
226 |
-
}
|
227 |
-
}, 5000);
|
228 |
});
|
229 |
});
|
230 |
</script>"""
|
231 |
|
232 |
-
|
233 |
-
bypass_script = ""
|
234 |
-
if BYPASS_SECRET:
|
235 |
-
bypass_script = f"<script>window.BYPASS_SECRET = '{BYPASS_SECRET}';</script>"
|
236 |
-
css = css.replace("BYPASS_SECRET_PLACEHOLDER", BYPASS_SECRET)
|
237 |
-
|
238 |
-
h = css + bypass_script + "<div class='grid'>"
|
239 |
-
|
240 |
for c in cards:
|
241 |
date=datetime.datetime.fromtimestamp(int(c["ts"])).strftime("%Y-%m-%d")
|
242 |
-
|
243 |
-
# URL์ protection bypass ์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ ์ถ๊ฐ
|
244 |
-
url = c['url']
|
245 |
-
if BYPASS_SECRET:
|
246 |
-
url_separator = '&' if '?' in url else '?'
|
247 |
-
url = f"{url}{url_separator}bypass={BYPASS_SECRET}"
|
248 |
-
|
249 |
h+=f"""
|
250 |
<div class='card'>
|
251 |
<div class='hdr'><p class='ttl'>{c['title']}</p><p class='date'>{date}</p></div>
|
252 |
<div class='frame'>
|
253 |
-
<iframe src="{url}" loading="lazy"
|
254 |
-
referrerpolicy="no-referrer"
|
255 |
-
sandbox="allow-scripts allow-same-origin allow-forms"
|
256 |
allow="accelerometer; camera; encrypted-media; gyroscope;"></iframe>
|
257 |
</div>
|
258 |
-
<div class='foot'><a class='link' href="{url}" target="_blank">์๋ณธโ</a></div>
|
259 |
</div>"""
|
260 |
h+="</div><p class='cnt'>Page "+str(pg)+" / "+str(total)+"</p>"
|
261 |
return h
|
262 |
-
|
263 |
# โโโโโโโโโโโโโโโโโโโโโ 6. Gradio Blocks UI โโโโโโโโโโโโโโโ
|
264 |
def build():
|
265 |
_init_best()
|
|
|
134 |
.hdr{padding:20px 24px;background:rgba(255,255,255,.75);backdrop-filter:blur(8px);border-bottom:1px solid #eee;}
|
135 |
.ttl{margin:0;font-size:1.15rem;font-weight:700;color:#333;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
|
136 |
.date{margin-top:4px;font-size:.85rem;color:#777;}
|
137 |
+
.frame{position:relative;width:100%;padding-top:60%;overflow:hidden;background:#f7f7f7;}
|
138 |
.frame iframe{position:absolute;top:0;left:0;width:142.857%;height:142.857%;
|
139 |
transform:scale(.7);transform-origin:top left;border:0;opacity:0;transition:opacity 0.3s;}
|
|
|
|
|
|
|
|
|
140 |
.frame-error {position:absolute;top:0;left:0;width:100%;height:100%;
|
141 |
display:flex;align-items:center;justify-content:center;
|
142 |
background:#f8f8f8;color:#666;font-size:14px;text-align:center;
|
|
|
146 |
border-radius:20px;font-size:12px;cursor:pointer;border:none;
|
147 |
transition:all 0.2s ease;}
|
148 |
.frame-error-btn:hover {background:#3a5dc8;transform:scale(1.05);}
|
149 |
+
.foot{padding:14px 24px;background:rgba(255,255,255,.85);backdrop-filter:blur(8px);text-align:right;}
|
150 |
+
.link{font-size:.85rem;font-weight:600;color:#4a6dd8;text-decoration:none;}
|
151 |
+
.cnt{text-align:center;font-size:.85rem;color:#555;margin:10px 0 40px;}
|
152 |
</style>
|
153 |
|
154 |
<script>
|
155 |
+
document.addEventListener('DOMContentLoaded', function() {
|
156 |
+
// iframe ๋ก๋ ์ค๋ฅ ์ฒ๋ฆฌ ํจ์
|
157 |
+
function handleIframeError(iframe) {
|
158 |
+
const container = iframe.parentNode;
|
159 |
+
const url = iframe.src;
|
160 |
+
iframe.style.display = 'none';
|
161 |
+
const errorDiv = document.createElement('div');
|
162 |
+
errorDiv.className = 'frame-error';
|
163 |
+
errorDiv.innerHTML = '<div class="frame-error-icon">๐ฎ</div>' +
|
164 |
+
'<div><strong>๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ฅผ ํ์ํ ์ ์์ต๋๋ค</strong></div>' +
|
165 |
+
'<div>์ ํญ์์ ์ง์ ํ์ธํด๋ณด์ธ์</div>' +
|
166 |
+
'<button class="frame-error-btn" onclick="window.open(\'' + url + '\', \'_blank\')">๊ฒ์ ์ด๊ธฐ</button>';
|
167 |
+
container.appendChild(errorDiv);
|
|
|
168 |
}
|
169 |
|
170 |
+
// iframe ๋ก๋ ์ฑ๊ณต ์ฒ๋ฆฌ
|
171 |
+
function handleIframeLoad(iframe) {
|
172 |
+
try {
|
173 |
+
// CORS ์ค๋ฅ ํ์ง ์๋
|
174 |
+
if (iframe.contentWindow && iframe.contentWindow.location && iframe.contentWindow.location.href) {
|
175 |
+
iframe.style.opacity = 1;
|
176 |
+
} else {
|
177 |
+
handleIframeError(iframe);
|
178 |
+
}
|
179 |
+
} catch (e) {
|
180 |
+
handleIframeError(iframe);
|
|
|
|
|
|
|
181 |
}
|
|
|
|
|
|
|
|
|
182 |
}
|
183 |
+
|
184 |
+
// ๋ชจ๋ iframe ์ฒ๋ฆฌ
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
185 |
const frames = document.querySelectorAll('iframe');
|
186 |
frames.forEach(frame => {
|
187 |
+
// iframe์ด ์ฒ์๋ถํฐ ๋ณด์ด๋๋ก ๊ธฐ๋ณธ ์ค๋ฅ UI ํ์
|
188 |
+
handleIframeError(frame);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
189 |
|
190 |
+
// ์ค์ iframe ๋ก๋ ์๋
|
191 |
frame.addEventListener('load', function() {
|
192 |
handleIframeLoad(this);
|
193 |
});
|
194 |
|
195 |
+
frame.addEventListener('error', function() {
|
196 |
+
handleIframeError(this);
|
197 |
+
});
|
|
|
|
|
|
|
198 |
});
|
199 |
});
|
200 |
</script>"""
|
201 |
|
202 |
+
h=css+"<div class='grid'>"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
203 |
for c in cards:
|
204 |
date=datetime.datetime.fromtimestamp(int(c["ts"])).strftime("%Y-%m-%d")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
205 |
h+=f"""
|
206 |
<div class='card'>
|
207 |
<div class='hdr'><p class='ttl'>{c['title']}</p><p class='date'>{date}</p></div>
|
208 |
<div class='frame'>
|
209 |
+
<iframe src="{c['url']}" loading="lazy"
|
|
|
|
|
210 |
allow="accelerometer; camera; encrypted-media; gyroscope;"></iframe>
|
211 |
</div>
|
212 |
+
<div class='foot'><a class='link' href="{c['url']}" target="_blank">์๋ณธโ</a></div>
|
213 |
</div>"""
|
214 |
h+="</div><p class='cnt'>Page "+str(pg)+" / "+str(total)+"</p>"
|
215 |
return h
|
|
|
216 |
# โโโโโโโโโโโโโโโโโโโโโ 6. Gradio Blocks UI โโโโโโโโโโโโโโโ
|
217 |
def build():
|
218 |
_init_best()
|