seawolf2357 commited on
Commit
4318a7e
ยท
verified ยท
1 Parent(s): 73bb808

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +160 -23
app.py CHANGED
@@ -1,4 +1,4 @@
1
- from flask import Flask, render_template, request, jsonify, session
2
  import requests
3
  from bs4 import BeautifulSoup
4
  import os
@@ -161,6 +161,49 @@ def scrape_all_like_status(token):
161
  def home():
162
  return render_template('index.html')
163
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164
  @app.route('/api/login', methods=['POST'])
165
  def login():
166
  token = request.form.get('token', '')
@@ -751,19 +794,29 @@ if __name__ == '__main__':
751
 
752
  <script>
753
  // DOM ์š”์†Œ ์ฐธ์กฐ
754
- const elements = {
755
- tokenInput: document.getElementById('tokenInput'),
756
- loginButton: document.getElementById('loginButton'),
757
- logoutButton: document.getElementById('logoutButton'),
758
- refreshButton: document.getElementById('refreshButton'),
759
- currentUser: document.getElementById('currentUser'),
760
- gridContainer: document.getElementById('gridContainer'),
761
- loadingIndicator: document.getElementById('loadingIndicator'),
762
- statusMessage: document.getElementById('statusMessage'),
763
- searchInput: document.getElementById('searchInput'),
764
- loginSection: document.getElementById('loginSection'),
765
- loggedInSection: document.getElementById('loggedInSection'),
766
- likeStatus: document.getElementById('likeStatus'),
 
 
 
 
 
 
 
 
 
 
767
  totalUrlCount: document.getElementById('totalUrlCount'),
768
  likedUrlCount: document.getElementById('likedUrlCount'),
769
  allUrlsBtn: document.getElementById('allUrlsBtn'),
@@ -816,11 +869,7 @@ if __name__ == '__main__':
816
  elements.likedUrlCount.textContent = likedCount;
817
  }
818
 
819
- // ์„ธ์…˜ ์ƒํƒœ
820
-
821
-
822
-
823
- // ์„ธ์…˜ ์ƒํƒœ ํ™•์ธ
824
  async function checkSessionStatus() {
825
  try {
826
  const response = await fetch('/api/session-status');
@@ -1065,13 +1114,101 @@ if __name__ == '__main__':
1065
  const iframeContainer = document.createElement('div');
1066
  iframeContainer.className = 'iframe-container';
1067
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1068
  const iframe = document.createElement('iframe');
1069
- iframe.src = item.url;
1070
  iframe.title = item.title;
1071
- iframe.sandbox = 'allow-scripts allow-same-origin allow-forms';
1072
- iframe.loading = 'lazy';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1073
 
1074
  iframeContainer.appendChild(iframe);
 
 
1075
  content.appendChild(iframeContainer);
1076
  } else {
1077
  // ์ž„๋ฒ ๋”ฉ ์—†๋Š” ๊ฒฝ์šฐ ๋งํฌ๋งŒ ํ‘œ์‹œ
@@ -1168,4 +1305,4 @@ if __name__ == '__main__':
1168
  </html>
1169
  ''')
1170
 
1171
- app.run(debug=True, host='0.0.0.0', port=7860)
 
1
+ from flask import Flask, render_template, request, jsonify, session, Response
2
  import requests
3
  from bs4 import BeautifulSoup
4
  import os
 
161
  def home():
162
  return render_template('index.html')
163
 
164
+ @app.route('/proxy/<path:url>')
165
+ def proxy(url):
166
+ try:
167
+ # URL ๋””์ฝ”๋”ฉ ๋ฐ ํ”„๋กœํ† ์ฝœ ์ถ”๊ฐ€ (ํ•„์š”ํ•œ ๊ฒฝ์šฐ)
168
+ if not url.startswith(('http://', 'https://')):
169
+ url = 'https://' + url
170
+
171
+ # ์š”์ฒญ ํ—ค๋” ์„ค์ •
172
+ headers = {
173
+ 'User-Agent': request.headers.get('User-Agent', 'Mozilla/5.0'),
174
+ 'Accept': 'text/html,application/xhtml+xml,application/xml',
175
+ 'Accept-Language': 'ko,en-US;q=0.9,en;q=0.8',
176
+ }
177
+
178
+ # ํ† ํฐ์ด ์žˆ์œผ๋ฉด ์ถ”๊ฐ€
179
+ if 'token' in session:
180
+ headers['Authorization'] = f"Bearer {session['token']}"
181
+
182
+ # ์›๊ฒฉ ์‚ฌ์ดํŠธ์— ์š”์ฒญ
183
+ response = requests.get(url, headers=headers, stream=True)
184
+
185
+ # ์›๊ฒฉ ์‚ฌ์ดํŠธ์˜ ์‘๋‹ต ํ—ค๋”๋ฅผ ๊ฐ€์ ธ์˜ด
186
+ response_headers = dict(response.headers)
187
+
188
+ # ํ”„๋ก์‹œ ์‘๋‹ต์—์„œ ์ œ์™ธํ•  ํ—ค๋”
189
+ excluded_headers = ['content-encoding', 'content-length', 'transfer-encoding', 'connection',
190
+ 'host', 'x-frame-options', 'content-security-policy']
191
+
192
+ # ํ•„์š”ํ•œ ํ—ค๋”๋งŒ ์œ ์ง€
193
+ headers = [(name, value) for name, value in response_headers.items()
194
+ if name.lower() not in excluded_headers]
195
+
196
+ # X-Frame-Options ๋ฐ CSP ํ—ค๋” ์ œ๊ฑฐ/๋ณ€๊ฒฝ
197
+ headers.append(('X-Frame-Options', 'ALLOWALL'))
198
+ headers.append(('Content-Security-Policy', "frame-ancestors 'self' *"))
199
+
200
+ # ์‘๋‹ต ์ƒ์„ฑ ๋ฐ ์ „์†ก
201
+ return Response(response.iter_content(chunk_size=1024), headers=headers,
202
+ status=response.status_code, content_type=response.headers.get('content-type'))
203
+ except Exception as e:
204
+ logger.error(f"ํ”„๋ก์‹œ ์˜ค๋ฅ˜: {str(e)}")
205
+ return jsonify({"error": "ํ”„๋ก์‹œ ์š”์ฒญ ์ฒ˜๋ฆฌ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค."}), 500
206
+
207
  @app.route('/api/login', methods=['POST'])
208
  def login():
209
  token = request.form.get('token', '')
 
794
 
795
  <script>
796
  // DOM ์š”์†Œ ์ฐธ์กฐ
797
+ // DOM ์š”์†Œ ์ฐธ์กฐ
798
+ const elements = {
799
+ tokenInput: document.getElementById('tokenInput'),
800
+ loginButton: document.getElementById('loginButton'),
801
+ logoutButton: document.getElementById('logoutButton'),
802
+ refreshButton: document.getElementById('refreshButton'),
803
+ currentUser: document.getElementById('currentUser'),
804
+ gridContainer: document.getElementById('gridContainer'),
805
+ loadingIndicator: document.getElementById('loadingIndicator'),
806
+ statusMessage: document.getElementById('statusMessage'),
807
+ searchInput: document.getElementById('searchInput'),
808
+ loginSection: document.getElementById('loginSection'),
809
+ loggedInSection: document.getElementById('loggedInSection'),
810
+ likeStatus: document.getElementById('likeStatus'),
811
+ totalUrlCount: document.getElementById('totalUrlCount'),
812
+ likedUrlCount: document.getElementById('likedUrlCount'),
813
+ allUrlsBtn: document.getElementById('allUrlsBtn'),
814
+ likedUrlsBtn: document.getElementById('likedUrlsBtn'),
815
+ embedToggle: document.getElementById('embedToggle')
816
+ };
817
+
818
+
819
+ likeStatus: document.getElementById('likeStatus'),
820
  totalUrlCount: document.getElementById('totalUrlCount'),
821
  likedUrlCount: document.getElementById('likedUrlCount'),
822
  allUrlsBtn: document.getElementById('allUrlsBtn'),
 
869
  elements.likedUrlCount.textContent = likedCount;
870
  }
871
 
872
+ // ์„ธ์…˜ ์ƒํƒœ ํ™•์ธ
 
 
 
 
873
  async function checkSessionStatus() {
874
  try {
875
  const response = await fetch('/api/session-status');
 
1114
  const iframeContainer = document.createElement('div');
1115
  iframeContainer.className = 'iframe-container';
1116
 
1117
+ // ๋กœ๋”ฉ ์ธ๋””์ผ€์ดํ„ฐ
1118
+ const loadingIndicator = document.createElement('div');
1119
+ loadingIndicator.className = 'loading-indicator';
1120
+ loadingIndicator.style.position = 'absolute';
1121
+ loadingIndicator.style.top = '0';
1122
+ loadingIndicator.style.left = '0';
1123
+ loadingIndicator.style.width = '100%';
1124
+ loadingIndicator.style.height = '100%';
1125
+ loadingIndicator.style.backgroundColor = '#f8f9fa';
1126
+ loadingIndicator.style.display = 'flex';
1127
+ loadingIndicator.style.alignItems = 'center';
1128
+ loadingIndicator.style.justifyContent = 'center';
1129
+ loadingIndicator.style.flexDirection = 'column';
1130
+ loadingIndicator.style.zIndex = '10';
1131
+
1132
+ const spinner = document.createElement('div');
1133
+ spinner.className = 'spinner';
1134
+ spinner.style.width = '40px';
1135
+ spinner.style.height = '40px';
1136
+ spinner.style.border = '4px solid #f3f3f3';
1137
+ spinner.style.borderTop = '4px solid #3498db';
1138
+ spinner.style.borderRadius = '50%';
1139
+ spinner.style.animation = 'spin 1s linear infinite';
1140
+
1141
+ const loadingText = document.createElement('div');
1142
+ loadingText.textContent = '์ฝ˜ํ…์ธ  ๋กœ๋”ฉ ์ค‘...';
1143
+ loadingText.style.marginTop = '10px';
1144
+
1145
+ loadingIndicator.appendChild(spinner);
1146
+ loadingIndicator.appendChild(loadingText);
1147
+
1148
+ // ํ”„๋ก์‹œ๋ฅผ ํ†ตํ•œ URL ์ธ์ฝ”๋”ฉ
1149
+ const originalUrl = item.url;
1150
+ const proxyUrl = `/proxy/${encodeURIComponent(originalUrl.replace(/^https?:\/\//, ''))}`;
1151
+
1152
+ // iframe ์ƒ์„ฑ
1153
  const iframe = document.createElement('iframe');
1154
+ iframe.src = proxyUrl;
1155
  iframe.title = item.title;
1156
+ iframe.width = '100%';
1157
+ iframe.height = '100%';
1158
+ iframe.style.border = 'none';
1159
+ iframe.style.backgroundColor = 'white';
1160
+
1161
+ // iframe ๋กœ๋“œ ์ด๋ฒคํŠธ
1162
+ iframe.onload = () => {
1163
+ loadingIndicator.style.display = 'none';
1164
+ };
1165
+
1166
+ // ๋กœ๋“œ ํƒ€์ž„์•„์›ƒ - 10์ดˆ ํ›„์—๋„ ๋กœ๋“œ๋˜์ง€ ์•Š์œผ๋ฉด ๋Œ€์ฒด UI ํ‘œ์‹œ
1167
+ let loadTimeout = setTimeout(() => {
1168
+ if (loadingIndicator.style.display !== 'none') {
1169
+ loadingIndicator.innerHTML = '';
1170
+
1171
+ const errorIcon = document.createElement('div');
1172
+ errorIcon.style.fontSize = '32px';
1173
+ errorIcon.textContent = 'โš ๏ธ';
1174
+
1175
+ const errorText = document.createElement('div');
1176
+ errorText.textContent = '์ฝ˜ํ…์ธ ๋ฅผ ๋กœ๋“œํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค';
1177
+ errorText.style.margin = '10px 0';
1178
+ errorText.style.fontWeight = 'bold';
1179
+
1180
+ const errorDesc = document.createElement('div');
1181
+ errorDesc.textContent = '์ด ์ฝ˜ํ…์ธ ๋Š” ์™ธ๋ถ€ ์ž„๋ฒ ๋”ฉ์„ ํ—ˆ์šฉํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.';
1182
+ errorDesc.style.fontSize = '0.9rem';
1183
+ errorDesc.style.marginBottom = '15px';
1184
+ errorDesc.style.textAlign = 'center';
1185
+
1186
+ const visitLink = document.createElement('a');
1187
+ visitLink.href = originalUrl;
1188
+ visitLink.target = '_blank';
1189
+ visitLink.textContent = '์ƒˆ ์ฐฝ์—์„œ ์ง์ ‘ ๋ฐฉ๋ฌธํ•˜๊ธฐ';
1190
+ visitLink.style.color = 'white';
1191
+ visitLink.style.backgroundColor = '#3498db';
1192
+ visitLink.style.padding = '8px 16px';
1193
+ visitLink.style.borderRadius = '4px';
1194
+ visitLink.style.textDecoration = 'none';
1195
+
1196
+ loadingIndicator.appendChild(errorIcon);
1197
+ loadingIndicator.appendChild(errorText);
1198
+ loadingIndicator.appendChild(errorDesc);
1199
+ loadingIndicator.appendChild(visitLink);
1200
+ }
1201
+ }, 10000);
1202
+
1203
+ // iframe ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ
1204
+ iframe.onerror = () => {
1205
+ clearTimeout(loadTimeout);
1206
+ loadingIndicator.innerHTML = '์ฝ˜ํ…์ธ ๋ฅผ ๋กœ๋“œํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. <a href="' + originalUrl + '" target="_blank">์ง์ ‘ ๋ฐฉ๋ฌธํ•˜๊ธฐ</a>';
1207
+ };
1208
 
1209
  iframeContainer.appendChild(iframe);
1210
+ iframeContainer.appendChild(loadingIndicator);
1211
+
1212
  content.appendChild(iframeContainer);
1213
  } else {
1214
  // ์ž„๋ฒ ๋”ฉ ์—†๋Š” ๊ฒฝ์šฐ ๋งํฌ๋งŒ ํ‘œ์‹œ
 
1305
  </html>
1306
  ''')
1307
 
1308
+ app.run(debug=True, host='0.0.0.0', port=7860)