Spaces:
Sleeping
Sleeping
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)
|