Update app.py
Browse files
app.py
CHANGED
|
@@ -8,6 +8,7 @@ from datetime import datetime, timedelta
|
|
| 8 |
from huggingface_hub import HfApi, hf_hub_download
|
| 9 |
from werkzeug.utils import secure_filename
|
| 10 |
import random
|
|
|
|
| 11 |
|
| 12 |
app = Flask(__name__)
|
| 13 |
app.secret_key = 'supersecretkey' # Замените на безопасный ключ в продакшене
|
|
@@ -116,7 +117,7 @@ def update_last_seen(data, username):
|
|
| 116 |
data['users'][username]['last_seen'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
| 117 |
save_data(data)
|
| 118 |
|
| 119 |
-
# Критический CSS
|
| 120 |
CRITICAL_CSS = '''
|
| 121 |
:root {
|
| 122 |
--primary: #ff4d6d;
|
|
@@ -144,7 +145,7 @@ body {
|
|
| 144 |
body.dark { background: var(--background-dark); color: var(--text-dark); }
|
| 145 |
'''
|
| 146 |
|
| 147 |
-
# Полный CSS
|
| 148 |
FULL_CSS = CRITICAL_CSS + '''
|
| 149 |
.container {
|
| 150 |
max-width: 1200px;
|
|
@@ -373,7 +374,7 @@ BASE_HTML = '''
|
|
| 373 |
</head>
|
| 374 |
<body>
|
| 375 |
<button class="menu-btn" onclick="toggleSidebar()">☰</button>
|
| 376 |
-
{{ NAV_HTML }}
|
| 377 |
<button class="theme-toggle" onclick="toggleTheme()">🌙</button>
|
| 378 |
<div class="container">
|
| 379 |
{% block content %}{% endblock %}
|
|
@@ -482,9 +483,10 @@ def register():
|
|
| 482 |
</div>
|
| 483 |
{% endblock %}
|
| 484 |
'''
|
| 485 |
-
import base64
|
| 486 |
return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
|
| 487 |
-
|
|
|
|
|
|
|
| 488 |
|
| 489 |
# Вход
|
| 490 |
@app.route('/login', methods=['GET', 'POST'])
|
|
@@ -556,9 +558,10 @@ def login():
|
|
| 556 |
</div>
|
| 557 |
{% endblock %}
|
| 558 |
'''
|
| 559 |
-
import base64
|
| 560 |
return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
|
| 561 |
-
|
|
|
|
|
|
|
| 562 |
|
| 563 |
# Выход
|
| 564 |
@app.route('/logout')
|
|
@@ -704,9 +707,11 @@ def feed():
|
|
| 704 |
{% endblock %}
|
| 705 |
{% endblock %}
|
| 706 |
'''
|
| 707 |
-
import base64
|
| 708 |
return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
|
| 709 |
-
|
|
|
|
|
|
|
|
|
|
| 710 |
|
| 711 |
# Страница поста
|
| 712 |
@app.route('/post/<post_id>', methods=['GET', 'POST'])
|
|
@@ -803,9 +808,11 @@ def post_page(post_id):
|
|
| 803 |
</div>
|
| 804 |
{% endblock %}
|
| 805 |
'''
|
| 806 |
-
import base64
|
| 807 |
return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
|
| 808 |
-
|
|
|
|
|
|
|
|
|
|
| 809 |
|
| 810 |
# Профиль пользователя
|
| 811 |
@app.route('/profile', methods=['GET', 'POST'])
|
|
@@ -905,16 +912,16 @@ def profile():
|
|
| 905 |
{% endif %}
|
| 906 |
<div class="profile-info">
|
| 907 |
<h1>{{ username }} <span class="status-dot {{ 'online' if is_online else 'offline' }}"></span></h1>
|
| 908 |
-
{% if not is_online %}
|
| 909 |
-
|
| 910 |
-
{% endif %}
|
| 911 |
-
<p>{{ bio }}</p>
|
| 912 |
-
{% if link %}
|
| 913 |
-
|
| 914 |
-
{% endif %}
|
| 915 |
-
<p>Views: {{ total_views }} | Likes: {{ total_likes }}</p>
|
| 916 |
-
<button class="btn" onclick="copyProfileLink()">Share</button>
|
| 917 |
-
</div>
|
| 918 |
</div>
|
| 919 |
<h2>Edit Profile</h2>
|
| 920 |
<form method="POST" enctype="multipart/form-data">
|
|
@@ -969,9 +976,11 @@ def profile():
|
|
| 969 |
{% endblock %}
|
| 970 |
{% endblock %}
|
| 971 |
'''
|
| 972 |
-
import base64
|
| 973 |
return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
|
| 974 |
-
|
|
|
|
|
|
|
|
|
|
| 975 |
|
| 976 |
# Профиль другого пользователя
|
| 977 |
@app.route('/profile/<username>')
|
|
@@ -1086,9 +1095,12 @@ def user_profile(username):
|
|
| 1086 |
{% endblock %}
|
| 1087 |
{% endblock %}
|
| 1088 |
'''
|
| 1089 |
-
import base64
|
| 1090 |
return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
|
| 1091 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1092 |
|
| 1093 |
# Загрузка контента
|
| 1094 |
@app.route('/upload', methods=['GET', 'POST'])
|
|
@@ -1202,9 +1214,10 @@ def upload():
|
|
| 1202 |
{% endblock %}
|
| 1203 |
{% endblock %}
|
| 1204 |
'''
|
| 1205 |
-
import base64
|
| 1206 |
return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
|
| 1207 |
-
|
|
|
|
|
|
|
| 1208 |
|
| 1209 |
# Общий чат
|
| 1210 |
@app.route('/chat', methods=['GET', 'POST'])
|
|
@@ -1347,10 +1360,12 @@ def chat():
|
|
| 1347 |
{% endblock %}
|
| 1348 |
'''
|
| 1349 |
user_posts = [p for p in data['posts'] if p['uploader'] == username] if is_authenticated else []
|
| 1350 |
-
import base64
|
| 1351 |
return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
|
| 1352 |
-
|
| 1353 |
-
|
|
|
|
|
|
|
|
|
|
| 1354 |
|
| 1355 |
# Страница пользователей
|
| 1356 |
@app.route('/users', methods=['GET', 'POST'])
|
|
@@ -1432,9 +1447,10 @@ def users():
|
|
| 1432 |
</div>
|
| 1433 |
{% endblock %}
|
| 1434 |
'''
|
| 1435 |
-
import base64
|
| 1436 |
return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
|
| 1437 |
-
|
|
|
|
|
|
|
| 1438 |
|
| 1439 |
# Список приватных сообщений
|
| 1440 |
@app.route('/messages', methods=['GET'])
|
|
@@ -1482,7 +1498,7 @@ def messages():
|
|
| 1482 |
body.dark .messages-container { background: var(--card-bg-dark); }
|
| 1483 |
h1 { font-size: 2em; background: linear-gradient(135deg, var(--primary), var(--accent)); -webkit-background-clip: text; color: transparent; margin-bottom: 20px; }
|
| 1484 |
.dialog-list { display: flex; flex-direction: column; gap: 10px; }
|
| 1485 |
-
.dialog-item { background: var(--card-bg-light); padding: 15px; border-radius: 10px; box-shadow: var(--shadow); transition: var(--transition); display: flex
|
| 1486 |
body.dark .dialog-item { background: var(--card-bg-dark); }
|
| 1487 |
.dialog-item:hover { transform: translateY(-3px); }
|
| 1488 |
.dialog-avatar { width: 40px; height: 40px; border-radius: 50%; object-fit: cover; box-shadow: var(--shadow); }
|
|
@@ -1524,9 +1540,10 @@ def messages():
|
|
| 1524 |
</div>
|
| 1525 |
{% endblock %}
|
| 1526 |
'''
|
| 1527 |
-
import base64
|
| 1528 |
return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
|
| 1529 |
-
|
|
|
|
|
|
|
| 1530 |
|
| 1531 |
# Приватный чат
|
| 1532 |
@app.route('/chat/<recipient>', methods=['GET', 'POST'])
|
|
@@ -1707,10 +1724,13 @@ def private_chat(recipient):
|
|
| 1707 |
{% endblock %}
|
| 1708 |
'''
|
| 1709 |
user_posts = [p for p in data['posts'] if p['uploader'] == username]
|
| 1710 |
-
import base64
|
| 1711 |
return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
|
| 1712 |
-
|
| 1713 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1714 |
|
| 1715 |
# Админ-панель
|
| 1716 |
@app.route('/admhosto', methods=['GET', 'POST'])
|
|
@@ -1819,9 +1839,11 @@ def admin_panel():
|
|
| 1819 |
{% endblock %}
|
| 1820 |
{% endblock %}
|
| 1821 |
'''
|
| 1822 |
-
import base64
|
| 1823 |
return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
|
| 1824 |
-
|
|
|
|
|
|
|
|
|
|
| 1825 |
|
| 1826 |
if __name__ == '__main__':
|
| 1827 |
backup_thread = threading.Thread(target=periodic_backup, daemon=True)
|
|
|
|
| 8 |
from huggingface_hub import HfApi, hf_hub_download
|
| 9 |
from werkzeug.utils import secure_filename
|
| 10 |
import random
|
| 11 |
+
import base64
|
| 12 |
|
| 13 |
app = Flask(__name__)
|
| 14 |
app.secret_key = 'supersecretkey' # Замените на безопасный ключ в продакшене
|
|
|
|
| 117 |
data['users'][username]['last_seen'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
| 118 |
save_data(data)
|
| 119 |
|
| 120 |
+
# Критический CSS
|
| 121 |
CRITICAL_CSS = '''
|
| 122 |
:root {
|
| 123 |
--primary: #ff4d6d;
|
|
|
|
| 145 |
body.dark { background: var(--background-dark); color: var(--text-dark); }
|
| 146 |
'''
|
| 147 |
|
| 148 |
+
# Полный CSS
|
| 149 |
FULL_CSS = CRITICAL_CSS + '''
|
| 150 |
.container {
|
| 151 |
max-width: 1200px;
|
|
|
|
| 374 |
</head>
|
| 375 |
<body>
|
| 376 |
<button class="menu-btn" onclick="toggleSidebar()">☰</button>
|
| 377 |
+
{{ NAV_HTML | safe }}
|
| 378 |
<button class="theme-toggle" onclick="toggleTheme()">🌙</button>
|
| 379 |
<div class="container">
|
| 380 |
{% block content %}{% endblock %}
|
|
|
|
| 483 |
</div>
|
| 484 |
{% endblock %}
|
| 485 |
'''
|
|
|
|
| 486 |
return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
|
| 487 |
+
NAV_HTML=NAV_HTML, is_authenticated=is_authenticated, username=username,
|
| 488 |
+
unread_count=unread_count, user_count=user_count, private_unread_count=private_unread_count,
|
| 489 |
+
is_online=is_online)
|
| 490 |
|
| 491 |
# Вход
|
| 492 |
@app.route('/login', methods=['GET', 'POST'])
|
|
|
|
| 558 |
</div>
|
| 559 |
{% endblock %}
|
| 560 |
'''
|
|
|
|
| 561 |
return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
|
| 562 |
+
NAV_HTML=NAV_HTML, is_authenticated=is_authenticated, username=username,
|
| 563 |
+
unread_count=unread_count, user_count=user_count, private_unread_count=private_unread_count,
|
| 564 |
+
is_online=is_online)
|
| 565 |
|
| 566 |
# Выход
|
| 567 |
@app.route('/logout')
|
|
|
|
| 707 |
{% endblock %}
|
| 708 |
{% endblock %}
|
| 709 |
'''
|
|
|
|
| 710 |
return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
|
| 711 |
+
NAV_HTML=NAV_HTML, is_user_online=lambda u: is_user_online(data, u), posts=posts,
|
| 712 |
+
is_authenticated=is_authenticated, username=username, repo_id=REPO_ID,
|
| 713 |
+
search_query=search_query, unread_count=unread_count, user_count=user_count,
|
| 714 |
+
private_unread_count=private_unread_count, is_online=is_online)
|
| 715 |
|
| 716 |
# Страница поста
|
| 717 |
@app.route('/post/<post_id>', methods=['GET', 'POST'])
|
|
|
|
| 808 |
</div>
|
| 809 |
{% endblock %}
|
| 810 |
'''
|
|
|
|
| 811 |
return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
|
| 812 |
+
NAV_HTML=NAV_HTML, is_user_online=lambda u: is_user_online(data, u), post=post,
|
| 813 |
+
repo_id=REPO_ID, is_authenticated=is_authenticated, username=username,
|
| 814 |
+
unread_count=unread_count, user_count=user_count, private_unread_count=private_unread_count,
|
| 815 |
+
is_online=is_online)
|
| 816 |
|
| 817 |
# Профиль пользователя
|
| 818 |
@app.route('/profile', methods=['GET', 'POST'])
|
|
|
|
| 912 |
{% endif %}
|
| 913 |
<div class="profile-info">
|
| 914 |
<h1>{{ username }} <span class="status-dot {{ 'online' if is_online else 'offline' }}"></span></h1>
|
| 915 |
+
{% if not is_online %}
|
| 916 |
+
<p style="color: rgba(0, 0, 0, 0.6);">Last seen: {{ last_seen }}</p>
|
| 917 |
+
{% endif %}
|
| 918 |
+
<p>{{ bio }}</p>
|
| 919 |
+
{% if link %}
|
| 920 |
+
<p><a href="{{ link }}" target="_blank" style="color: var(--primary);">{{ link }}</a></p>
|
| 921 |
+
{% endif %}
|
| 922 |
+
<p>Views: {{ total_views }} | Likes: {{ total_likes }}</p>
|
| 923 |
+
<button class="btn" onclick="copyProfileLink()">Share</button>
|
| 924 |
+
</div>
|
| 925 |
</div>
|
| 926 |
<h2>Edit Profile</h2>
|
| 927 |
<form method="POST" enctype="multipart/form-data">
|
|
|
|
| 976 |
{% endblock %}
|
| 977 |
{% endblock %}
|
| 978 |
'''
|
|
|
|
| 979 |
return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
|
| 980 |
+
NAV_HTML=NAV_HTML, username=username, user_posts=user_posts, total_views=total_views,
|
| 981 |
+
total_likes=total_likes, bio=bio, link=link, avatar=avatar, repo_id=REPO_ID,
|
| 982 |
+
is_authenticated=is_authenticated, unread_count=unread_count, user_count=user_count,
|
| 983 |
+
private_unread_count=private_unread_count, is_online=is_online, last_seen=last_seen)
|
| 984 |
|
| 985 |
# Профиль другого пользователя
|
| 986 |
@app.route('/profile/<username>')
|
|
|
|
| 1095 |
{% endblock %}
|
| 1096 |
{% endblock %}
|
| 1097 |
'''
|
|
|
|
| 1098 |
return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
|
| 1099 |
+
NAV_HTML=NAV_HTML, user_posts=user_posts, total_views=total_views, total_likes=total_likes,
|
| 1100 |
+
bio=bio, link=link, avatar=avatar, username=username, profile_is_online=profile_is_online,
|
| 1101 |
+
last_seen=last_seen, repo_id=REPO_ID, is_authenticated=is_authenticated,
|
| 1102 |
+
unread_count=unread_count, user_count=user_count, private_unread_count=private_unread_count,
|
| 1103 |
+
is_online=is_online)
|
| 1104 |
|
| 1105 |
# Загрузка контента
|
| 1106 |
@app.route('/upload', methods=['GET', 'POST'])
|
|
|
|
| 1214 |
{% endblock %}
|
| 1215 |
{% endblock %}
|
| 1216 |
'''
|
|
|
|
| 1217 |
return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
|
| 1218 |
+
NAV_HTML=NAV_HTML, is_authenticated=is_authenticated, username=username,
|
| 1219 |
+
unread_count=unread_count, user_count=user_count, private_unread_count=private_unread_count,
|
| 1220 |
+
is_online=is_online)
|
| 1221 |
|
| 1222 |
# Общий чат
|
| 1223 |
@app.route('/chat', methods=['GET', 'POST'])
|
|
|
|
| 1360 |
{% endblock %}
|
| 1361 |
'''
|
| 1362 |
user_posts = [p for p in data['posts'] if p['uploader'] == username] if is_authenticated else []
|
|
|
|
| 1363 |
return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
|
| 1364 |
+
NAV_HTML=NAV_HTML, chat_messages=chat_messages, username=username,
|
| 1365 |
+
is_authenticated=is_authenticated, repo_id=REPO_ID, posts=data['posts'],
|
| 1366 |
+
user_posts=user_posts, unread_count=unread_count, user_count=user_count,
|
| 1367 |
+
private_unread_count=private_unread_count, is_online=is_online,
|
| 1368 |
+
is_user_online=lambda u: is_user_online(data, u))
|
| 1369 |
|
| 1370 |
# Страница пользователей
|
| 1371 |
@app.route('/users', methods=['GET', 'POST'])
|
|
|
|
| 1447 |
</div>
|
| 1448 |
{% endblock %}
|
| 1449 |
'''
|
|
|
|
| 1450 |
return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
|
| 1451 |
+
NAV_HTML=NAV_HTML, user_list=user_list, username=username, is_authenticated=is_authenticated,
|
| 1452 |
+
repo_id=REPO_ID, unread_count=unread_count, user_count=user_count,
|
| 1453 |
+
private_unread_count=private_unread_count, is_online=is_online, search_query=search_query)
|
| 1454 |
|
| 1455 |
# Список приватных сообщений
|
| 1456 |
@app.route('/messages', methods=['GET'])
|
|
|
|
| 1498 |
body.dark .messages-container { background: var(--card-bg-dark); }
|
| 1499 |
h1 { font-size: 2em; background: linear-gradient(135deg, var(--primary), var(--accent)); -webkit-background-clip: text; color: transparent; margin-bottom: 20px; }
|
| 1500 |
.dialog-list { display: flex; flex-direction: column; gap: 10px; }
|
| 1501 |
+
.dialog-item { background: var(--card-bg-light); padding: 15px; border-radius: 10px; box-shadow: var(--shadow); transition: var(--transition); display: flex align-items: center; gap: 10px; }
|
| 1502 |
body.dark .dialog-item { background: var(--card-bg-dark); }
|
| 1503 |
.dialog-item:hover { transform: translateY(-3px); }
|
| 1504 |
.dialog-avatar { width: 40px; height: 40px; border-radius: 50%; object-fit: cover; box-shadow: var(--shadow); }
|
|
|
|
| 1540 |
</div>
|
| 1541 |
{% endblock %}
|
| 1542 |
'''
|
|
|
|
| 1543 |
return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
|
| 1544 |
+
NAV_HTML=NAV_HTML, dialogs=dialogs, username=username, is_authenticated=is_authenticated,
|
| 1545 |
+
repo_id=REPO_ID, unread_count=unread_count, user_count=user_count,
|
| 1546 |
+
private_unread_count=private_unread_count, is_online=is_online)
|
| 1547 |
|
| 1548 |
# Приватный чат
|
| 1549 |
@app.route('/chat/<recipient>', methods=['GET', 'POST'])
|
|
|
|
| 1724 |
{% endblock %}
|
| 1725 |
'''
|
| 1726 |
user_posts = [p for p in data['posts'] if p['uploader'] == username]
|
|
|
|
| 1727 |
return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
|
| 1728 |
+
NAV_HTML=NAV_HTML, private_messages=private_messages, recipient=recipient,
|
| 1729 |
+
username=username, is_authenticated=is_authenticated, repo_id=REPO_ID,
|
| 1730 |
+
posts=data['posts'], user_posts=user_posts, unread_count=unread_count,
|
| 1731 |
+
user_count=user_count, private_unread_count=private_unread_count,
|
| 1732 |
+
is_online=is_online, is_user_online=lambda u: is_user_online(data, u),
|
| 1733 |
+
avatar=avatar, recipient_avatar=recipient_avatar, recipient_online=recipient_online)
|
| 1734 |
|
| 1735 |
# Админ-панель
|
| 1736 |
@app.route('/admhosto', methods=['GET', 'POST'])
|
|
|
|
| 1839 |
{% endblock %}
|
| 1840 |
{% endblock %}
|
| 1841 |
'''
|
|
|
|
| 1842 |
return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
|
| 1843 |
+
NAV_HTML=NAV_HTML, posts=posts, is_authenticated=is_authenticated, username=username,
|
| 1844 |
+
repo_id=REPO_ID, search_query=search_query, unread_count=unread_count,
|
| 1845 |
+
user_count=user_count, private_unread_count=private_unread_count,
|
| 1846 |
+
is_online=is_online, is_user_online=lambda u: is_user_online(data, u))
|
| 1847 |
|
| 1848 |
if __name__ == '__main__':
|
| 1849 |
backup_thread = threading.Thread(target=periodic_backup, daemon=True)
|