ginipick commited on
Commit
5a08d41
ยท
verified ยท
1 Parent(s): d68f6ae

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +39 -86
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
- // iframe ๋กœ๋“œ ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ ํ•จ์ˆ˜
157
- function handleIframeError(iframe) {
158
- const container = iframe.parentNode;
159
- const originalUrl = iframe.src;
160
- iframe.style.display = 'none';
161
- const errorDiv = document.createElement('div');
162
- errorDiv.className = 'frame-error';
163
-
164
- // ์šฐํšŒ ๋น„๋ฐ€ํ‚ค๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ URL์— ์ถ”๊ฐ€ (Protection Bypass)
165
- let bypassUrl = originalUrl;
166
- if (typeof BYPASS_SECRET !== 'undefined' && BYPASS_SECRET) {
167
- // URL์— ์ด๋ฏธ ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธ
168
- const hasQuery = bypassUrl.includes('?');
169
- bypassUrl = bypassUrl + (hasQuery ? '&' : '?') + 'bypass=' + encodeURIComponent(BYPASS_SECRET);
170
  }
171
 
172
- errorDiv.innerHTML = '<div class="frame-error-icon">๐Ÿ”’</div>' +
173
- '<div><strong>๋ณดํ˜ธ๋œ ๋ฐฐํฌ์ž…๋‹ˆ๋‹ค</strong></div>' +
174
- '<div>๋ณด์•ˆ ์„ค์ •์œผ๋กœ ์ธํ•ด iframe์—์„œ ํ‘œ์‹œํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค</div>' +
175
- '<button class="frame-error-btn" onclick="window.open(\'' + bypassUrl + '\', \'_blank\')">์ƒˆ ํƒญ์—์„œ ์—ด๊ธฐ</button>';
176
-
177
- container.appendChild(errorDiv);
178
- }
179
-
180
- // iframe ๋กœ๋“œ ์„ฑ๊ณต ์ฒ˜๋ฆฌ
181
- function handleIframeLoad(iframe) {
182
- try {
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
- // URL์— ์šฐํšŒ ํŒŒ๋ผ๋ฏธํ„ฐ ์ถ”๊ฐ€ (Protection Bypass)
206
- if (window.BYPASS_SECRET) {
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
- // 5์ดˆ ํ›„์—๋„ ๋กœ๋“œ๋˜์ง€ ์•Š์œผ๋ฉด ์˜ค๋ฅ˜๋กœ ๊ฐ„์ฃผ
223
- setTimeout(function() {
224
- if(frame.style.opacity !== '1') {
225
- handleIframeError(frame);
226
- }
227
- }, 5000);
228
  });
229
  });
230
  </script>"""
231
 
232
- # ์šฐํšŒ ๋น„๋ฐ€ํ‚ค๊ฐ€ ์žˆ๋‹ค๋ฉด JavaScript์— ์ฃผ์ž…
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()