diff --git "a/app.py" "b/app.py"
--- "a/app.py"
+++ "b/app.py"
@@ -1,4 +1,5 @@
from flask import Flask, render_template_string, request, redirect, url_for, session, flash
+from flask_caching import Cache # Добавляем кэширование
import json
import os
import logging
@@ -8,19 +9,22 @@ from datetime import datetime, timedelta
from huggingface_hub import HfApi, hf_hub_download
from werkzeug.utils import secure_filename
import random
-import base64
app = Flask(__name__)
-app.secret_key = 'supersecretkey' # Замените на безопасный ключ в продакшене
+app.secret_key = os.getenv("FLASK_SECRET_KEY", "supersecretkey") # Безопасный ключ из переменной окружения
DATA_FILE = 'data_adusis.json'
REPO_ID = "Eluza133/w1f9"
-HF_TOKEN_WRITE = os.getenv("HF_TOKEN")
+HF_TOKEN_WRITE = os.getenv("HF_TOKEN") # Токен для записи
HF_TOKEN_READ = os.getenv("HF_TOKEN_READ") or HF_TOKEN_WRITE
-# Логирование
-logging.basicConfig(level=logging.DEBUG)
+# Настройка кэширования
+cache = Cache(app, config={'CACHE_TYPE': 'simple'})
-# Функции для работы с данными
+# Настройка логирования
+logging.basicConfig(level=logging.INFO)
+
+# Функции работы с базой данных
+@cache.memoize(timeout=300) # Кэшируем данные на 5 минут
def load_data():
try:
download_db_from_hf()
@@ -29,13 +33,14 @@ def load_data():
if not isinstance(data, dict):
logging.warning("Данные не в формате dict, инициализация пустой базы")
return {'posts': [], 'users': {}, 'general_chat': [], 'private_chats': {}}
- for key in ['posts', 'users', 'general_chat', 'private_chats']:
- if key not in data:
- data[key] = [] if key in ['posts', 'general_chat'] else {}
+ data.setdefault('posts', [])
+ data.setdefault('users', {})
+ data.setdefault('general_chat', [])
+ data.setdefault('private_chats', {})
for user in data['users']:
- for field in ['last_chat_visit', 'last_private_visit', 'last_seen']:
- if field not in data['users'][user]:
- data['users'][user][field] = '1970-01-01 00:00:00'
+ data['users'][user].setdefault('last_chat_visit', '1970-01-01 00:00:00')
+ data['users'][user].setdefault('last_private_visit', '1970-01-01 00:00:00')
+ data['users'][user].setdefault('last_seen', '1970-01-01 00:00:00')
logging.info("Данные успешно загружены")
return data
except Exception as e:
@@ -47,6 +52,7 @@ def save_data(data):
with open(DATA_FILE, 'w', encoding='utf-8') as file:
json.dump(data, file, ensure_ascii=False, indent=4)
upload_db_to_hf()
+ cache.clear() # Очищаем кэш после сохранения
logging.info("Данные сохранены и загружены на HF")
except Exception as e:
logging.error(f"Ошибка при сохранении данных: {e}")
@@ -87,7 +93,7 @@ def download_db_from_hf():
def periodic_backup():
while True:
upload_db_to_hf()
- time.sleep(800)
+ time.sleep(1800) # Увеличиваем интервал до 30 минут для снижения нагрузки
def get_unread_count(data, username):
if username not in data['users']:
@@ -117,20 +123,20 @@ def update_last_seen(data, username):
data['users'][username]['last_seen'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
save_data(data)
-# Критический CSS
-CRITICAL_CSS = '''
+# Обновленный стиль
+BASE_STYLE = '''
:root {
--primary: #ff4d6d;
--secondary: #00ddeb;
--accent: #8b5cf6;
--background-light: #fef9f1;
--background-dark: #1f1a44;
- --card-bg-light: rgba(255, 255, 255, 0.95);
- --card-bg-dark: rgba(50, 45, 80, 0.95);
+ --card-bg: rgba(255, 255, 255, 0.9);
+ --card-bg-dark: rgba(50, 45, 80, 0.9);
--text-light: #2a1e5a;
--text-dark: #e8e1ff;
- --shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
- --glass-bg: rgba(255, 255, 255, 0.15);
+ --shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
+ --glass-bg: rgba(255, 255, 255, 0.1);
--transition: all 0.3s ease;
--online: #34c759;
--offline: #ff3b30;
@@ -141,17 +147,12 @@ body {
background: var(--background-light);
color: var(--text-light);
line-height: 1.6;
-}
-body.dark { background: var(--background-dark); color: var(--text-dark); }
-'''
-
-# Полный CSS
-FULL_CSS = CRITICAL_CSS + '''
-.container {
- max-width: 1200px;
- margin: 20px auto;
- padding: 0 15px;
transition: var(--transition);
+ overflow-x: hidden;
+}
+body.dark {
+ background: var(--background-dark);
+ color: var(--text-dark);
}
.sidebar {
position: fixed;
@@ -160,23 +161,23 @@ FULL_CSS = CRITICAL_CSS + '''
width: 280px;
height: 100%;
background: var(--glass-bg);
- backdrop-filter: blur(20px);
+ backdrop-filter: blur(15px);
padding: 20px;
box-shadow: var(--shadow);
z-index: 1000;
- transform: translateX(0);
- transition: var(--transition);
- overflow-y: auto;
+ transition: transform var(--transition);
+}
+.sidebar.hidden {
+ transform: translateX(-100%);
}
-.sidebar.hidden { transform: translateX(-100%); }
.sidebar-header {
display: flex;
align-items: center;
- gap: 10px;
+ gap: 12px;
margin-bottom: 30px;
}
.nav-brand {
- font-size: 1.5em;
+ font-size: 1.6em;
font-weight: 800;
background: linear-gradient(135deg, var(--primary), var(--accent));
-webkit-background-clip: text;
@@ -196,14 +197,14 @@ FULL_CSS = CRITICAL_CSS + '''
.nav-link {
display: flex;
align-items: center;
- gap: 10px;
+ gap: 12px;
padding: 12px 20px;
- background: var(--card-bg-light);
+ background: var(--card-bg);
color: var(--text-light);
text-decoration: none;
border-radius: 12px;
font-size: 1em;
- font-weight: 600;
+ font-weight: 500;
transition: var(--transition);
position: relative;
}
@@ -212,19 +213,53 @@ body.dark .nav-link {
color: var(--text-dark);
}
.nav-link:hover {
- transform: translateX(5px);
+ transform: scale(1.02);
background: var(--primary);
color: white;
- box-shadow: 0 4px 15px rgba(255, 77, 109, 0.4);
+ box-shadow: 0 4px 16px rgba(255, 77, 109, 0.3);
}
.nav-link .badge {
position: absolute;
- right: 10px;
+ right: 12px;
background: var(--secondary);
color: white;
- padding: 3px 6px;
+ padding: 3px 8px;
border-radius: 10px;
font-size: 0.75em;
+ font-weight: 700;
+}
+.logout-btn {
+ background: var(--secondary);
+ color: white;
+}
+.logout-btn:hover {
+ background: #00b8c5;
+}
+.menu-btn {
+ display: none;
+ font-size: 24px;
+ background: var(--glass-bg);
+ border: none;
+ color: var(--primary);
+ cursor: pointer;
+ position: fixed;
+ top: 15px;
+ left: 15px;
+ z-index: 1001;
+ padding: 10px;
+ border-radius: 50%;
+ box-shadow: var(--shadow);
+ transition: var(--transition);
+}
+.menu-btn:hover {
+ background: var(--primary);
+ color: white;
+}
+.container {
+ margin: 20px auto 20px 300px;
+ max-width: 1200px;
+ padding: 20px;
+ transition: var(--transition);
}
.btn {
padding: 12px 24px;
@@ -236,11 +271,15 @@ body.dark .nav-link {
font-size: 1em;
font-weight: 600;
transition: var(--transition);
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
box-shadow: var(--shadow);
}
.btn:hover {
transform: scale(1.03);
background: #e6415f;
+ box-shadow: 0 6px 20px rgba(255, 77, 109, 0.4);
}
input, textarea, select {
width: 100%;
@@ -252,10 +291,14 @@ input, textarea, select {
color: var(--text-light);
font-size: 1em;
transition: var(--transition);
+ box-shadow: inset 0 2px 8px rgba(0, 0, 0, 0.05);
+}
+body.dark input, body.dark textarea, body.dark select {
+ color: var(--text-dark);
}
-body.dark input, body.dark textarea, body.dark select { color: var(--text-dark); }
input:focus, textarea:focus, select:focus {
outline: none;
+ background: rgba(255, 255, 255, 0.15);
box-shadow: 0 0 0 3px var(--primary);
}
.modal {
@@ -265,16 +308,19 @@ input:focus, textarea:focus, select:focus {
left: 0;
width: 100%;
height: 100%;
- background: rgba(0, 0, 0, 0.9);
+ background: rgba(0, 0, 0, 0.8);
z-index: 2000;
justify-content: center;
align-items: center;
+ transition: opacity var(--transition);
}
.modal img, .modal video {
max-width: 90%;
- max-height: 90vh;
- border-radius: 15px;
+ max-height: 90%;
+ object-fit: contain;
+ border-radius: 16px;
box-shadow: var(--shadow);
+ animation: zoomIn 0.3s ease;
}
.theme-toggle {
position: fixed;
@@ -294,22 +340,6 @@ input:focus, textarea:focus, select:focus {
background: var(--accent);
color: white;
}
-.menu-btn {
- display: none;
- position: fixed;
- top: 15px;
- left: 15px;
- background: var(--glass-bg);
- border: none;
- padding: 10px;
- border-radius: 50%;
- cursor: pointer;
- font-size: 24px;
- box-shadow: var(--shadow);
- z-index: 1001;
- transition: var(--transition);
-}
-.menu-btn:hover { background: var(--primary); color: white; }
.status-dot {
width: 8px;
height: 8px;
@@ -319,25 +349,41 @@ input:focus, textarea:focus, select:focus {
}
.online { background: var(--online); }
.offline { background: var(--offline); }
-@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
-@keyframes slideIn { from { transform: translateY(20px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }
-@media (max-width: 768px) {
+@keyframes zoomIn {
+ from { opacity: 0; transform: scale(0.95); }
+ to { opacity: 1; transform: scale(1); }
+}
+@media (max-width: 900px) {
.sidebar {
width: 100%;
max-width: 280px;
transform: translateX(-100%);
}
- .sidebar.active { transform: translateX(0); }
- .menu-btn { display: block; }
- .container { margin: 60px 10px 20px; }
- .theme-toggle { top: 60px; right: 10px; }
+ .sidebar.active {
+ transform: translateX(0);
+ }
+ .menu-btn {
+ display: block;
+ }
+ .container {
+ margin: 70px 15px 20px 15px;
+ max-width: calc(100% - 30px);
+ }
+ .theme-toggle {
+ top: 70px;
+ }
+}
+@media (max-width: 480px) {
+ .nav-brand { font-size: 1.4em; }
+ .nav-link { font-size: 0.9em; padding: 10px 16px; }
+ .btn { padding: 10px 18px; font-size: 0.9em; }
}
'''
NAV_HTML = '''
'''
-BASE_HTML = '''
+# Регистрация
+@app.route('/register', methods=['GET', 'POST'])
+def register():
+ if request.method == 'POST':
+ username = request.form.get('username')
+ password = request.form.get('password')
+ data = load_data()
+
+ if username in data['users']:
+ flash('Пользователь уже существует!')
+ return redirect(url_for('register'))
+
+ data['users'][username] = {
+ 'password': password,
+ 'bio': '',
+ 'link': '',
+ 'avatar': None,
+ 'last_chat_visit': '1970-01-01 00:00:00',
+ 'last_private_visit': '1970-01-01 00:00:00',
+ 'last_seen': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
+ }
+ save_data(data)
+ flash('Регистрация успешна! Пожалуйста, войдите.')
+ return redirect(url_for('login'))
+
+ is_authenticated = 'username' in session
+ username = session.get('username', None)
+ data = load_data()
+ unread_count = get_unread_count(data, username) if is_authenticated else 0
+ private_unread_count = get_private_unread_count(data, username) if is_authenticated else 0
+ user_count = len(data['users'])
+ is_online = is_user_online(data, username) if is_authenticated else False
+
+ html = '''
@@ -367,125 +446,91 @@ BASE_HTML = '''
- {% block title %}{% endblock %}
-
-
-
+ Register - Content Hub
+
+
- {{ NAV_HTML | safe }}
+ ''' + NAV_HTML + '''
- {% block content %}{% endblock %}
-
-
-
![Modal content]()
+
Register
+ {% with messages = get_flashed_messages() %}
+ {% if messages %}
+ {% for message in messages %}
+
{{ message }}
+ {% endfor %}
+ {% endif %}
+ {% endwith %}
+
+
Already have an account? Login
- {% block scripts %}{% endblock %}
'''
-
-# Регистрация
-@app.route('/register', methods=['GET', 'POST'])
-def register():
- if request.method == 'POST':
- username = request.form.get('username')
- password = request.form.get('password')
- data = load_data()
- if username in data['users']:
- flash('Пользователь уже существует!')
- return redirect(url_for('register'))
- data['users'][username] = {
- 'password': password, 'bio': '', 'link': '', 'avatar': None,
- 'last_chat_visit': '1970-01-01 00:00:00', 'last_private_visit': '1970-01-01 00:00:00',
- 'last_seen': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
- }
- save_data(data)
- flash('Регистрация успешна! Пожалуйста, войдите.')
- return redirect(url_for('login'))
-
- is_authenticated = 'username' in session
- username = session.get('username', None)
- data = load_data()
- unread_count = get_unread_count(data, username) if is_authenticated else 0
- private_unread_count = get_private_unread_count(data, username) if is_authenticated else 0
- user_count = len(data['users'])
- is_online = is_user_online(data, username) if is_authenticated else False
-
- html = BASE_HTML.replace('{% block title %}{% endblock %}', 'Register - Content Hub') + '''
-{% block content %}
-
-
-
Register
- {% with messages = get_flashed_messages() %}
- {% if messages %}
- {% for message in messages %}
-
{{ message }}
- {% endfor %}
- {% endif %}
- {% endwith %}
-
-
-
-{% endblock %}
-'''
- return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
- NAV_HTML=NAV_HTML, is_authenticated=is_authenticated, username=username,
- unread_count=unread_count, user_count=user_count, private_unread_count=private_unread_count,
- is_online=is_online)
+ return render_template_string(html, is_authenticated=is_authenticated, username=username, unread_count=unread_count, user_count=user_count, private_unread_count=private_unread_count, is_online=is_online)
# Вход
@app.route('/login', methods=['GET', 'POST'])
@@ -494,6 +539,7 @@ def login():
if request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
+
if username in data['users'] and data['users'][username]['password'] == password:
session['username'] = username
session.permanent = True
@@ -501,7 +547,7 @@ def login():
return redirect(url_for('feed'))
flash('Неверное имя пользователя или пароль!')
return redirect(url_for('login'))
-
+
is_authenticated = 'username' in session
username = session.get('username', None)
if is_authenticated:
@@ -510,56 +556,99 @@ def login():
private_unread_count = get_private_unread_count(data, username) if is_authenticated else 0
user_count = len(data['users'])
is_online = is_user_online(data, username) if is_authenticated else False
-
- html = BASE_HTML.replace('{% block title %}{% endblock %}', 'Login - Content Hub') + '''
-{% block content %}
-
-
-
Login
- {% with messages = get_flashed_messages() %}
- {% if messages %}
- {% for message in messages %}
-
{{ message }}
- {% endfor %}
- {% endif %}
- {% endwith %}
-
-
-
-{% endblock %}
+
+ html = '''
+
+
+
+
+
+
+ Login - Content Hub
+
+
+
+
+
+ ''' + NAV_HTML + '''
+
+
+
Login
+ {% with messages = get_flashed_messages() %}
+ {% if messages %}
+ {% for message in messages %}
+
{{ message }}
+ {% endfor %}
+ {% endif %}
+ {% endwith %}
+
+
Don't have an account? Register
+
+
+
+
'''
- return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
- NAV_HTML=NAV_HTML, is_authenticated=is_authenticated, username=username,
- unread_count=unread_count, user_count=user_count, private_unread_count=private_unread_count,
- is_online=is_online)
+ return render_template_string(html, is_authenticated=is_authenticated, username=username, unread_count=unread_count, user_count=user_count, private_unread_count=private_unread_count, is_online=is_online)
# Выход
@app.route('/logout')
@@ -571,7 +660,7 @@ def logout():
session.pop('username', None)
return redirect(url_for('feed'))
-# Увеличение просмотров
+# Увеличение счетчика просмотров
@app.route('/increment_view/', methods=['POST'])
def increment_view(post_id):
data = load_data()
@@ -600,227 +689,374 @@ def feed():
if search_query:
posts = [post for post in posts if search_query in post['title'].lower() or search_query in post['description'].lower()]
- html = BASE_HTML.replace('{% block title %}{% endblock %}', 'Adusis - QoS, BBC, BNWO HUB') + '''
-{% block content %}
-
-Content Feed
-
-
-
-
-{% block scripts %}
-
-{% endblock %}
-{% endblock %}
-'''
- return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
- NAV_HTML=NAV_HTML, is_user_online=lambda u: is_user_online(data, u), posts=posts,
- is_authenticated=is_authenticated, username=username, repo_id=REPO_ID,
- search_query=search_query, unread_count=unread_count, user_count=user_count,
- private_unread_count=private_unread_count, is_online=is_online)
-
-# Страница поста
-@app.route('/post/', methods=['GET', 'POST'])
-def post_page(post_id):
- data = load_data()
- username = session.get('username', None)
- if username:
- update_last_seen(data, username)
- post = next((p for p in data['posts'] if p['id'] == post_id), None)
- if not post:
- return "Пост не найден", 404
-
- is_authenticated = 'username' in session
- unread_count = get_unread_count(data, username) if is_authenticated else 0
- private_unread_count = get_private_unread_count(data, username) if is_authenticated else 0
- user_count = len(data['users'])
- is_online = is_user_online(data, username) if is_authenticated else False
- post['views'] = post.get('views', 0) + 1
- save_data(data)
-
- if request.method == 'POST' and is_authenticated:
- if 'like' in request.form:
- if username not in post.get('likes', []):
- post['likes'] = post.get('likes', []) + [username]
- else:
- post['likes'] = [user for user in post.get('likes', []) if user != username]
- save_data(data)
- elif 'comment' in request.form:
- comment_text = request.form.get('comment')
- if comment_text:
- post['comments'] = post.get('comments', []) + [{'user': username, 'text': comment_text, 'date': datetime.now().strftime('%Y-%m-%d %H:%M:%S')}]
- save_data(data)
-
- html = BASE_HTML.replace('{% block title %}{% endblock %}', f"{post['title']} - Content Hub") + '''
-{% block content %}
-
-
-
{{ post['title'] }}
- {% if post['type'] == 'video' %}
-
- {% else %}
-
![{{ post['title'] }}](https://huggingface.co/datasets/{{ repo_id }}/resolve/main/{{ post['type'] }}s/{{ post['filename'] }})
- {% endif %}
-
{{ post['description'] }}
-
By: {{ post['uploader'] }} | {{ post['upload_date'] }}
-
Views: {{ post['views'] }} | Likes: {{ post['likes']|length }}
- {% if is_authenticated %}
-
-
- {% endif %}
-
Comments
- {% for comment in post.get('comments', []) %}
-
- {% endfor %}
-
Back to Feed
- {% if not is_authenticated %}
-
Login to like and comment.
- {% endif %}
-
-{% endblock %}
-'''
- return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
- NAV_HTML=NAV_HTML, is_user_online=lambda u: is_user_online(data, u), post=post,
- repo_id=REPO_ID, is_authenticated=is_authenticated, username=username,
- unread_count=unread_count, user_count=user_count, private_unread_count=private_unread_count,
- is_online=is_online)
-
-# Профиль пользователя
-@app.route('/profile', methods=['GET', 'POST'])
-def profile():
- if 'username' not in session:
- flash('Войдите, чтобы просмотреть свой профиль!')
- return redirect(url_for('login'))
-
- data = load_data()
- username = session['username']
- update_last_seen(data, username)
- user_posts = sorted([p for p in data['posts'] if p['uploader'] == username], key=lambda x: datetime.strptime(x['upload_date'], '%Y-%m-%d %H:%M:%S'), reverse=True)
+ html = '''
+
+
+
+
+
+
+
+ Adusis - QoS, BBC, BNWO HUB
+
+
+
+
+
+ ''' + NAV_HTML + '''
+
+
+
+
![]()
+
+
+
+
+'''
+ return render_template_string(html, posts=posts, is_authenticated=is_authenticated, username=username, repo_id=REPO_ID, search_query=search_query, unread_count=unread_count, user_count=user_count, private_unread_count=private_unread_count, is_online=is_online, is_user_online=lambda u: is_user_online(data, u))
+
+# Страница поста
+@app.route('/post/', methods=['GET', 'POST'])
+def post_page(post_id):
+ data = load_data()
+ username = session.get('username', None)
+ if username:
+ update_last_seen(data, username)
+ post = next((p for p in data['posts'] if p['id'] == post_id), None)
+ if not post:
+ return "Пост не найден", 404
+
+ is_authenticated = 'username' in session
+ unread_count = get_unread_count(data, username) if is_authenticated else 0
+ private_unread_count = get_private_unread_count(data, username) if is_authenticated else 0
+ user_count = len(data['users'])
+ is_online = is_user_online(data, username) if is_authenticated else False
+ post['views'] = post.get('views', 0) + 1
+ save_data(data)
+
+ if request.method == 'POST' and is_authenticated:
+ if 'like' in request.form:
+ if username not in post.get('likes', []):
+ post['likes'] = post.get('likes', []) + [username]
+ else:
+ post['likes'] = [user for user in post.get('likes', []) if user != username]
+ save_data(data)
+ elif 'comment' in request.form:
+ comment_text = request.form.get('comment')
+ if comment_text:
+ post['comments'] = post.get('comments', []) + [{'user': username, 'text': comment_text, 'date': datetime.now().strftime('%Y-%m-%d %H:%M:%S')}]
+ save_data(data)
+
+ html = '''
+
+
+
+
+
+
+ {{ post['title'] }} - Content Hub
+
+
+
+
+
+ ''' + NAV_HTML + '''
+
+
+
{{ post['title'] }}
+ {% if post['type'] == 'video' %}
+
+ {% else %}
+
![{{ post['title'] }}](https://huggingface.co/datasets/{{ repo_id }}/resolve/main/{{ post['type'] }}s/{{ post['filename'] }})
+ {% endif %}
+
{{ post['description'] }}
+
By: {{ post['uploader'] }} | {{ post['upload_date'] }}
+
Views: {{ post['views'] }} | Likes: {{ post['likes']|length }}
+ {% if is_authenticated %}
+
+
+ {% endif %}
+
Comments
+ {% for comment in post.get('comments', []) %}
+
+ {% endfor %}
+
Back to Feed
+ {% if not is_authenticated %}
+
Login to like and comment.
+ {% endif %}
+
+
+
![]()
+
+
+
+
+'''
+ return render_template_string(html, post=post, repo_id=REPO_ID, is_authenticated=is_authenticated, username=username, unread_count=unread_count, user_count=user_count, private_unread_count=private_unread_count, is_online=is_online, is_user_online=lambda u: is_user_online(data, u))
+
+# Профиль пользователя
+@app.route('/profile', methods=['GET', 'POST'])
+def profile():
+ if 'username' not in session:
+ flash('Войдите, чтобы просмотреть свой профиль!')
+ return redirect(url_for('login'))
+
+ data = load_data()
+ username = session['username']
+ update_last_seen(data, username)
+ user_posts = sorted([p for p in data['posts'] if p['uploader'] == username], key=lambda x: datetime.strptime(x['upload_date'], '%Y-%m-%d %H:%M:%S'), reverse=True)
is_authenticated = 'username' in session
unread_count = get_unread_count(data, username)
private_unread_count = get_private_unread_count(data, username)
@@ -869,113 +1105,224 @@ def profile():
save_data(data)
return redirect(url_for('profile'))
- html = BASE_HTML.replace('{% block title %}{% endblock %}', f"Profile - {username} - Content Hub") + '''
-{% block content %}
-
-
-Edit Profile
-
-Add Post
-Your Posts
-
- {% if user_posts %}
- {% for post in user_posts %}
-
+
+
![]()
+
+
+
+
'''
- return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
- NAV_HTML=NAV_HTML, username=username, user_posts=user_posts, total_views=total_views,
- total_likes=total_likes, bio=bio, link=link, avatar=avatar, repo_id=REPO_ID,
- is_authenticated=is_authenticated, unread_count=unread_count, user_count=user_count,
- private_unread_count=private_unread_count, is_online=is_online, last_seen=last_seen)
+ return render_template_string(html, username=username, user_posts=user_posts, total_views=total_views, total_likes=total_likes, bio=bio, link=link, avatar=avatar, repo_id=REPO_ID, is_authenticated=is_authenticated, unread_count=unread_count, user_count=user_count, private_unread_count=private_unread_count, is_online=is_online, last_seen=last_seen)
# Профиль другого пользователя
@app.route('/profile/
')
@@ -1002,104 +1349,200 @@ def user_profile(username):
profile_is_online = is_user_online(data, username)
last_seen = user_data.get('last_seen', 'Never')
- html = BASE_HTML.replace('{% block title %}{% endblock %}', f"Profile - {username} - Content Hub") + '''
-{% block content %}
-
-
-{{ username }}'s Posts
-
- {% if user_posts %}
- {% for post in user_posts %}
-
+
+
![]()
+
+
+
+
'''
- return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
- NAV_HTML=NAV_HTML, user_posts=user_posts, total_views=total_views, total_likes=total_likes,
- bio=bio, link=link, avatar=avatar, username=username, profile_is_online=profile_is_online,
- last_seen=last_seen, repo_id=REPO_ID, is_authenticated=is_authenticated,
- unread_count=unread_count, user_count=user_count, private_unread_count=private_unread_count,
- is_online=is_online)
+ return render_template_string(html, username=username, user_posts=user_posts, total_views=total_views, total_likes=total_likes, bio=bio, link=link, avatar=avatar, repo_id=REPO_ID, is_authenticated=is_authenticated, unread_count=unread_count, user_count=user_count, private_unread_count=private_unread_count, is_online=is_online, profile_is_online=profile_is_online, last_seen=last_seen)
# Загрузка контента
@app.route('/upload', methods=['GET', 'POST'])
def upload():
if 'username' not in session:
+ flash('Войдите, чтобы загрузить контент!')
return redirect(url_for('login'))
data = load_data()
@@ -1113,12 +1556,12 @@ def upload():
if request.method == 'POST':
title = request.form.get('title')
- description = request.form.get('description', '')
+ description = request.form.get('description')
file = request.files.get('file')
if not file or not title:
- flash('Title and file are required!')
+ flash('Заголовок и файл обязательны!')
return redirect(url_for('upload'))
-
+
filename = secure_filename(file.filename)
temp_path = os.path.join('uploads', filename)
os.makedirs('uploads', exist_ok=True)
@@ -1152,65 +1595,124 @@ def upload():
'comments': []
})
save_data(data)
+
if os.path.exists(temp_path):
os.remove(temp_path)
return redirect(url_for('profile'))
- html = BASE_HTML.replace('{% block title %}{% endblock %}', 'Upload Content - Content Hub') + '''
-{% block content %}
-
-
-{% block scripts %}
-
-{% endblock %}
-{% endblock %}
+
+
{{ comment['user'] }} ({{ comment['date'] }}): {{ comment['text'] }}
-