Spaces:
Running
Running
Update app.py
Browse files
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 |
-
|
755 |
-
|
756 |
-
|
757 |
-
|
758 |
-
|
759 |
-
|
760 |
-
|
761 |
-
|
762 |
-
|
763 |
-
|
764 |
-
|
765 |
-
|
766 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 =
|
1070 |
iframe.title = item.title;
|
1071 |
-
iframe.
|
1072 |
-
iframe.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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)
|