diff --git "a/app.py" "b/app.py"
--- "a/app.py"
+++ "b/app.py"
@@ -1,6 +1,4 @@
from flask import Flask, render_template_string, request, redirect, url_for, session, flash
-from flask_caching import Cache
-from flask_compress import Compress
import json
import os
import logging
@@ -9,26 +7,19 @@ import time
from datetime import datetime, timedelta
from huggingface_hub import HfApi, hf_hub_download
from werkzeug.utils import secure_filename
-from PIL import Image
-import pyheif
import random
app = Flask(__name__)
app.secret_key = 'supersecretkey' # Замените на безопасный ключ в продакшене
DATA_FILE = 'data_adusis.json'
-REPO_ID = "Eluza133/W1f9"
-HF_TOKEN_WRITE = os.getenv("HF_TOKEN") # Токен для записи
+REPO_ID = "Eluza133/A12d12s12"
+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'})
-Compress(app)
-
-# Функции работы с базой данных
-@cache.memoize(timeout=60) # Кэш на 60 секунд
+# Функции для работы с данными
def load_data():
try:
download_db_from_hf()
@@ -37,21 +28,13 @@ def load_data():
if not isinstance(data, dict):
logging.warning("Данные не в формате dict, инициализация пустой базы")
return {'posts': [], 'users': {}, 'general_chat': [], 'private_chats': {}}
- if 'posts' not in data:
- data['posts'] = []
- if 'users' not in data:
- data['users'] = {}
- if 'general_chat' not in data:
- data['general_chat'] = []
- if 'private_chats' not in data:
- data['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 {}
for user in data['users']:
- if 'last_chat_visit' not in data['users'][user]:
- data['users'][user]['last_chat_visit'] = '1970-01-01 00:00:00'
- if 'last_private_visit' not in data['users'][user]:
- data['users'][user]['last_private_visit'] = '1970-01-01 00:00:00'
- if 'last_seen' not in data['users'][user]:
- data['users'][user]['last_seen'] = '1970-01-01 00:00:00'
+ 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'
logging.info("Данные успешно загружены")
return data
except Exception as e:
@@ -64,7 +47,6 @@ def save_data(data):
json.dump(data, file, ensure_ascii=False, indent=4)
upload_db_to_hf()
logging.info("Данные сохранены и загружены на HF")
- cache.delete_memoized(load_data) # Очистка кэша после сохранения
except Exception as e:
logging.error(f"Ошибка при сохранении данных: {e}")
raise
@@ -127,95 +109,99 @@ def is_user_online(data, username):
if username not in data['users']:
return False
last_seen = datetime.strptime(data['users'][username]['last_seen'], '%Y-%m-%d %H:%M:%S')
- return (datetime.now() - last_seen).total_seconds() < 300 # Онлайн, если активен в последние 5 минут
+ return (datetime.now() - last_seen).total_seconds() < 300
def update_last_seen(data, username):
if username in data['users']:
data['users'][username]['last_seen'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
save_data(data)
-# Исходный стиль
-BASE_STYLE = '''
+# Критический CSS для быстрой загрузки
+CRITICAL_CSS = '''
:root {
- --primary: #ff4d6d; /* Vivid pink-red */
- --secondary: #00ddeb; /* Bright cyan */
- --accent: #8b5cf6; /* Electric purple */
- --background-light: #fef9f1; /* Soft cream */
- --background-dark: #1f1a44; /* Deep indigo */
+ --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);
--text-light: #2a1e5a;
--text-dark: #e8e1ff;
--shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
--glass-bg: rgba(255, 255, 255, 0.15);
- --transition: all 0.4s ease-in-out;
- --online: #34c759; /* Green for online */
- --offline: #ff3b30; /* Red for offline */
+ --transition: all 0.3s ease;
+ --online: #34c759;
+ --offline: #ff3b30;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'Inter', sans-serif;
background: var(--background-light);
color: var(--text-light);
- line-height: 1.8;
- transition: var(--transition);
- overflow-x: hidden;
+ line-height: 1.6;
}
-body.dark {
- background: var(--background-dark);
- color: var(--text-dark);
+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);
}
.sidebar {
position: fixed;
top: 0;
left: 0;
- width: 300px;
+ width: 280px;
height: 100%;
background: var(--glass-bg);
backdrop-filter: blur(20px);
- padding: 30px 20px;
+ padding: 20px;
box-shadow: var(--shadow);
z-index: 1000;
transform: translateX(0);
- transition: transform 0.4s cubic-bezier(0.68, -0.55, 0.27, 1.55);
-}
-.sidebar.hidden {
- transform: translateX(-100%);
+ transition: var(--transition);
+ overflow-y: auto;
}
+.sidebar.hidden { transform: translateX(-100%); }
.sidebar-header {
display: flex;
align-items: center;
- gap: 15px;
- margin-bottom: 40px;
+ gap: 10px;
+ margin-bottom: 30px;
}
.nav-brand {
- font-size: 1.8em;
- font-weight: 900;
+ font-size: 1.5em;
+ font-weight: 800;
background: linear-gradient(135deg, var(--primary), var(--accent));
-webkit-background-clip: text;
color: transparent;
}
.logo {
- width: 40px;
- height: 40px;
- border-radius: 14px;
+ width: 36px;
+ height: 36px;
+ border-radius: 12px;
box-shadow: var(--shadow);
}
.nav-links {
display: flex;
flex-direction: column;
- gap: 18px;
+ gap: 12px;
}
.nav-link {
display: flex;
align-items: center;
- gap: 15px;
- padding: 15px 25px;
+ gap: 10px;
+ padding: 12px 20px;
background: var(--card-bg-light);
color: var(--text-light);
text-decoration: none;
- border-radius: 14px;
- font-size: 1.1em;
+ border-radius: 12px;
+ font-size: 1em;
font-weight: 600;
transition: var(--transition);
position: relative;
@@ -228,90 +214,48 @@ body.dark .nav-link {
transform: translateX(5px);
background: var(--primary);
color: white;
- box-shadow: 0 6px 20px rgba(255, 77, 109, 0.4);
+ box-shadow: 0 4px 15px rgba(255, 77, 109, 0.4);
}
.nav-link .badge {
position: absolute;
- right: 15px;
- background: var(--secondary);
- color: white;
- padding: 4px 8px;
- border-radius: 12px;
- font-size: 0.8em;
- font-weight: 700;
-}
-.logout-btn {
+ right: 10px;
background: var(--secondary);
color: white;
-}
-.logout-btn:hover {
- background: #00b8c5;
-}
-.menu-btn {
- display: none;
- font-size: 30px;
- background: var(--glass-bg);
- border: none;
- color: var(--primary);
- cursor: pointer;
- position: fixed;
- top: 20px;
- left: 20px;
- z-index: 1001;
- padding: 12px;
- border-radius: 50%;
- box-shadow: var(--shadow);
- transition: var(--transition);
-}
-.menu-btn:hover {
- background: var(--primary);
- color: white;
-}
-.container {
- margin: 30px auto 30px 320px;
- max-width: 1300px;
- padding: 30px;
- transition: var(--transition);
+ padding: 3px 6px;
+ border-radius: 10px;
+ font-size: 0.75em;
}
.btn {
- padding: 14px 28px;
+ padding: 12px 24px;
background: var(--primary);
color: white;
border: none;
- border-radius: 14px;
+ border-radius: 12px;
cursor: pointer;
- font-size: 1.1em;
- font-weight: 700;
+ font-size: 1em;
+ font-weight: 600;
transition: var(--transition);
- display: inline-flex;
- align-items: center;
- gap: 10px;
box-shadow: var(--shadow);
}
.btn:hover {
- transform: scale(1.05);
+ transform: scale(1.03);
background: #e6415f;
- box-shadow: 0 8px 30px rgba(255, 77, 109, 0.5);
}
input, textarea, select {
width: 100%;
- padding: 14px;
- margin: 14px 0;
+ padding: 12px;
+ margin: 10px 0;
border: none;
- border-radius: 14px;
+ border-radius: 12px;
background: var(--glass-bg);
color: var(--text-light);
- font-size: 1.1em;
+ font-size: 1em;
transition: var(--transition);
- box-shadow: inset 0 3px 10px 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.2);
- box-shadow: 0 0 0 4px var(--primary);
+ box-shadow: 0 0 0 3px var(--primary);
}
.modal {
display: none;
@@ -320,98 +264,79 @@ input:focus, textarea:focus, select:focus {
left: 0;
width: 100%;
height: 100%;
- background: rgba(0, 0, 0, 0.85);
+ background: rgba(0, 0, 0, 0.9);
z-index: 2000;
justify-content: center;
align-items: center;
- transition: opacity 0.4s ease;
}
.modal img, .modal video {
- max-width: 95%;
- max-height: 95%;
- object-fit: contain;
- border-radius: 20px;
+ max-width: 90%;
+ max-height: 90vh;
+ border-radius: 15px;
box-shadow: var(--shadow);
- animation: zoomIn 0.4s ease;
}
.theme-toggle {
position: fixed;
- top: 20px;
- right: 20px;
+ top: 15px;
+ right: 15px;
background: var(--glass-bg);
border: none;
- padding: 12px;
+ padding: 10px;
border-radius: 50%;
cursor: pointer;
- font-size: 24px;
+ font-size: 20px;
box-shadow: var(--shadow);
transition: var(--transition);
}
.theme-toggle:hover {
- transform: rotate(180deg);
+ transform: rotate(90deg);
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: 10px;
- height: 10px;
+ width: 8px;
+ height: 8px;
border-radius: 50%;
display: inline-block;
margin-left: 5px;
}
-.online {
- background: var(--online);
-}
-.offline {
- background: var(--offline);
-}
-@keyframes zoomIn {
- from { opacity: 0; transform: scale(0.9); }
- to { opacity: 1; transform: scale(1); }
-}
-@media (max-width: 900px) {
+.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) {
.sidebar {
width: 100%;
- max-width: 300px;
+ max-width: 280px;
transform: translateX(-100%);
}
- .sidebar.active {
- transform: translateX(0);
- }
- .menu-btn {
- display: block;
- }
- .container {
- margin: 80px 15px 30px 15px;
- max-width: calc(100% - 30px);
- }
- .theme-toggle {
- top: 80px;
- right: 15px;
- }
- .post-grid {
- grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
- }
-}
-@media (max-width: 480px) {
- .nav-brand {
- font-size: 1.5em;
- }
- .nav-link {
- font-size: 1em;
- padding: 12px 20px;
- }
- .btn {
- padding: 12px 20px;
- font-size: 1em;
- }
+ .sidebar.active { transform: translateX(0); }
+ .menu-btn { display: block; }
+ .container { margin: 60px 10px 20px; }
+ .theme-toggle { top: 60px; right: 10px; }
}
'''
NAV_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 = '''
+BASE_HTML = '''
@@ -474,87 +366,125 @@ def register():
- Register - Content Hub
-
-
+ {% block title %}{% endblock %} - Content Hub
+
+
+
- ''' + NAV_HTML + '''
+ {{ NAV_HTML }}
🌙
-
Register
- {% with messages = get_flashed_messages() %}
- {% if messages %}
- {% for message in messages %}
-
{{ message }}
- {% endfor %}
- {% endif %}
- {% endwith %}
-
-
Already have an account? Login
+ {% block content %}{% endblock %}
+
+
+
+ {% block scripts %}{% endblock %}
'''
- 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('/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 + '''
+{% block title %}Register{% endblock %}
+{% block content %}
+
+
+
Register
+ {% with messages = get_flashed_messages() %}
+ {% if messages %}
+ {% for message in messages %}
+
{{ message }}
+ {% endfor %}
+ {% endif %}
+ {% endwith %}
+
+
+
+{% endblock %}
+'''
+ import base64
+ return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
+ NAV_HTML=NAV_HTML.format(**locals()), **locals())
# Вход
@app.route('/login', methods=['GET', 'POST'])
@@ -563,7 +493,6 @@ 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
@@ -571,7 +500,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:
@@ -580,95 +509,56 @@ 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 = '''
-
-
-
-
-
-
- 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
-
-
-
-
+
+ html = BASE_HTML + '''
+{% block title %}Login{% endblock %}
+{% block content %}
+
+
+
Login
+ {% with messages = get_flashed_messages() %}
+ {% if messages %}
+ {% for message in messages %}
+
{{ message }}
+ {% endfor %}
+ {% endif %}
+ {% endwith %}
+
+
+
+{% endblock %}
'''
- 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)
+ import base64
+ return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
+ NAV_HTML=NAV_HTML.format(**locals()), **locals())
# Выход
@app.route('/logout')
@@ -680,7 +570,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()
@@ -698,7 +588,7 @@ def feed():
username = session.get('username', None)
if username:
update_last_seen(data, username)
- posts = sorted(data.get('posts', []), key=lambda x: datetime.strptime(x['upload_date'], '%Y-%m-%d %H:%M:%S'), reverse=True)[:20] # Только первые 20 постов
+ posts = sorted(data.get('posts', []), 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) if is_authenticated else 0
private_unread_count = get_private_unread_count(data, username) if is_authenticated else 0
@@ -709,180 +599,114 @@ 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 = '''
-
-
-
-
-
-
-
- Adusis - QoS, BBC, BNWO HUB
-
-
-
-
-
- ''' + NAV_HTML + '''
- 🌙
-
-
-
-
-
-
-
+ html = BASE_HTML + '''
+{% block title %}Adusis - QoS, BBC, BNWO HUB{% endblock %}
+{% block content %}
+
+Content Feed
+
+
+
+
+{% block scripts %}
+
+{% endblock %}
+{% endblock %}
'''
- 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))
+ import base64
+ return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
+ NAV_HTML=NAV_HTML.format(**locals()), is_user_online=lambda u: is_user_online(data, u), **locals())
# Страница поста
@app.route('/post/', methods=['GET', 'POST'])
@@ -916,142 +740,72 @@ def post_page(post_id):
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 %}
-
- {% 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 %}
-
-
-
-
-
-
-
+ html = BASE_HTML + '''
+{% block title %}{{ post['title'] }}{% endblock %}
+{% block content %}
+
+
+
{{ post['title'] }}
+ {% if post['type'] == 'video' %}
+
+
+
+ {% else %}
+
+ {% 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, 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))
+ import base64
+ return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
+ NAV_HTML=NAV_HTML.format(**locals()), is_user_online=lambda u: is_user_online(data, u), **locals())
# Профиль пользователя
@app.route('/profile', methods=['GET', 'POST'])
@@ -1112,213 +866,112 @@ def profile():
save_data(data)
return redirect(url_for('profile'))
- html = '''
-
-
-
-
-
-
- Profile - {{ username }} - Content Hub
-
-
-
-
-
- ''' + NAV_HTML + '''
- 🌙
-
-
+{% block scripts %}
+
+{% endblock %}
+{% endblock %}
'''
- 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)
+ import base64
+ return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
+ NAV_HTML=NAV_HTML.format(**locals()), **locals())
# Профиль другого пол��зователя
@app.route('/profile/
')
@@ -1345,187 +998,102 @@ def user_profile(username):
profile_is_online = is_user_online(data, username)
last_seen = user_data.get('last_seen', 'Never')
- html = '''
-
-
-
-
-
-
- Profile - {{ username }} - Content Hub
-
-
-
-
-
- ''' + NAV_HTML + '''
- 🌙
-
-
+{% block scripts %}
+
+{% endblock %}
+{% endblock %}
'''
- return render_template_string(html, username=username, session_username=session_username, user_posts=user_posts, total_views=total_views, total_likes=total_likes, bio=bio, link=link, avatar=avatar, 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)
+ import base64
+ return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
+ NAV_HTML=NAV_HTML.format(**locals()), **locals())
# Загрузка контента
@app.route('/upload', methods=['GET', 'POST'])
def upload():
if 'username' not in session:
- flash('Войдите, чтобы загрузить контент!')
return redirect(url_for('login'))
data = load_data()
@@ -1541,37 +1109,16 @@ def upload():
title = request.form.get('title')
description = request.form.get('description', '')
file = request.files.get('file')
-
if not file or not title:
- flash('Заполните все поля!')
+ flash('Title and file are required!')
return redirect(url_for('upload'))
-
+
filename = secure_filename(file.filename)
temp_path = os.path.join('uploads', filename)
os.makedirs('uploads', exist_ok=True)
file.save(temp_path)
-
- # Определяем тип файла
+
file_type = 'video' if filename.lower().endswith(('.mp4', '.mov', '.avi')) else 'photo'
- if filename.lower().endswith(('.heic', '.heif')):
- # Конверсия HEIC в JPEG
- heif_file = pyheif.read(temp_path)
- image = Image.frombytes(
- heif_file.mode,
- heif_file.size,
- heif_file.data,
- "raw",
- heif_file.mode,
- heif_file.stride,
- )
- new_filename = filename.rsplit('.', 1)[0] + '.jpg'
- temp_new_path = os.path.join('uploads', new_filename)
- image.save(temp_new_path, "JPEG")
- os.remove(temp_path)
- temp_path = temp_new_path
- filename = new_filename
- file_type = 'photo'
-
api = HfApi()
api.upload_file(
path_or_fileobj=temp_path,
@@ -1599,113 +1146,65 @@ def upload():
'comments': []
})
save_data(data)
-
if os.path.exists(temp_path):
os.remove(temp_path)
return redirect(url_for('profile'))
- html = '''
-
-
-
-
-
-
-
Upload Content - Content Hub
-
-
-
-
-
- ''' + NAV_HTML + '''
-
🌙
-
-
-
-
+ xhr.send(formData);
+ };
+
+{% endblock %}
+{% endblock %}
'''
- return render_template_string(html, username=username, is_authenticated=is_authenticated, unread_count=unread_count, user_count=user_count, private_unread_count=private_unread_count, is_online=is_online)
+ import base64
+ return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
+ NAV_HTML=NAV_HTML.format(**locals()), **locals())
# Общий чат
@app.route('/chat', methods=['GET', 'POST'])
@@ -1731,10 +1230,7 @@ def chat():
file = request.files.get('file')
post_id = request.form.get('post_id')
- message_data = {
- 'sender': username,
- 'time': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
- }
+ message_data = {'sender': username, 'time': datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
if message:
message_data['text'] = message
@@ -1744,26 +1240,7 @@ def chat():
temp_path = os.path.join('uploads', filename)
os.makedirs('uploads', exist_ok=True)
file.save(temp_path)
-
file_type = 'video' if filename.lower().endswith(('.mp4', '.mov', '.avi')) else 'photo'
- if filename.lower().endswith(('.heic', '.heif')):
- heif_file = pyheif.read(temp_path)
- image = Image.frombytes(
- heif_file.mode,
- heif_file.size,
- heif_file.data,
- "raw",
- heif_file.mode,
- heif_file.stride,
- )
- new_filename = filename.rsplit('.', 1)[0] + '.jpg'
- temp_new_path = os.path.join('uploads', new_filename)
- image.save(temp_new_path, "JPEG")
- os.remove(temp_path)
- temp_path = temp_new_path
- filename = new_filename
- file_type = 'photo'
-
api = HfApi()
file_path = f"chat_files/general/{filename}"
api.upload_file(
@@ -1787,226 +1264,93 @@ def chat():
if 'text' in message_data or 'file' in message_data or 'post_id' in message_data:
data['general_chat'].append(message_data)
save_data(data)
-
return redirect(url_for('chat'))
- html = '''
-
-
-
-
-
-
-
General Chat - Content Hub
-
-
-
-
-
- ''' + NAV_HTML + '''
-
🌙
-
-
General Chat
-
- {% for message in chat_messages %}
-
-
{{ message['sender'] }}
-
-
({{ message['time'] }}) :
- {% if 'text' in message %}
-
{{ message['text'] }}
+ html = BASE_HTML + '''
+{% block title %}General Chat{% endblock %}
+{% block content %}
+
+
+
General Chat
+
+ {% for message in chat_messages %}
+
+
{{ message['sender'] }}
+
+
({{ message['time'] }}) :
+ {% if 'text' in message %}
{{ message['text'] }}
{% endif %}
+ {% if 'file' in message %}
+ {% if message['file_type'] == 'video' %}
+
+
+
+ {% else %}
+
{% endif %}
- {% if 'file' in message %}
- {% if message['file_type'] == 'video' %}
-
-
-
- {% else %}
-
+ {% endif %}
+ {% if 'post_id' in message %}
+ {% with post = posts|selectattr('id', 'equalto', message['post_id'])|first %}
+ {% if post %}
+
Shared: {{ post['title'] }}
{% endif %}
- {% endif %}
- {% if 'post_id' in message %}
- {% with post = posts|selectattr('id', 'equalto', message['post_id'])|first %}
- {% if post %}
-
Shared: {{ post['title'] }}
- {% endif %}
- {% endwith %}
- {% endif %}
-
- {% endfor %}
-
- {% if is_authenticated %}
-
-
-
-
- Share a post (optional)
- {% for post in user_posts %}
- {{ post['title'] }}
- {% endfor %}
-
- Send
-
- {% else %}
-
Login to send messages.
- {% endif %}
-
-
-
+ {% endwith %}
+ {% endif %}
+
+ {% endfor %}
-
-
-
+ {% if is_authenticated %}
+
+
+
+
+ Share a post (optional)
+ {% for post in user_posts %}
+ {{ post['title'] }}
+ {% endfor %}
+
+ Send
+
+ {% else %}
+
Login to send messages.
+ {% endif %}
+
+{% block scripts %}
+
+{% endblock %}
+{% endblock %}
'''
user_posts = [p for p in data['posts'] if p['uploader'] == username] if is_authenticated else []
- return render_template_string(html,
- chat_messages=chat_messages,
- username=username,
- is_authenticated=is_authenticated,
- repo_id=REPO_ID,
- posts=data['posts'],
- user_posts=user_posts,
- 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))
+ import base64
+ return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
+ NAV_HTML=NAV_HTML.format(**locals()), posts=data['posts'], user_posts=user_posts,
+ is_user_online=lambda u: is_user_online(data, u), **locals())
# Страница пользователей
@app.route('/users', methods=['GET', 'POST'])
@@ -2026,164 +1370,73 @@ def users():
if search_query:
user_list = [u for u in user_list if search_query in u[0].lower()]
- html = '''
-
-
-
-
-
-
-
Users - Content Hub
-
-
-
-
-
- ''' + NAV_HTML + '''
-
🌙
-
-
Users ({{ user_count }})
-
-
-
- 🔍
-
-
-
- {% for user, avatar, online in user_list %}
- {% if user != username %}
-
- {% if avatar %}
-
- {% else %}
-
+ html = BASE_HTML + '''
+{% block title %}Users{% endblock %}
+{% block content %}
+
+
+
Users ({{ user_count }})
+
+
+
+ 🔍
+
+
+
+ {% for user, avatar, online in user_list %}
+ {% if user != username %}
+
+ {% if avatar %}
+
+ {% else %}
+
+ {% endif %}
+
- {% endif %}
- {% endfor %}
-
+
+ {% endif %}
+ {% endfor %}
-
-
-
+
+{% endblock %}
'''
- return render_template_string(html, user_list=user_list, username=username, is_authenticated=is_authenticated, repo_id=REPO_ID, unread_count=unread_count, user_count=user_count, private_unread_count=private_unread_count, is_online=is_online, search_query=search_query)
+ import base64
+ return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
+ NAV_HTML=NAV_HTML.format(**locals()), **locals())
-# Страница сообщений (список приватных диалогов)
+# Список приватных сообщений
@app.route('/messages', methods=['GET'])
def messages():
if 'username' not in session:
@@ -2202,7 +1455,7 @@ def messages():
dialogs = {}
for chat_key, messages in data['private_chats'].items():
user1, user2 = chat_key.split('_')
- if username not in (user1, user2): # Пропускаем чаты, где пользователь не участвует
+ if username not in (user1, user2):
continue
other_user = user1 if user2 == username else user2
last_message = messages[-1] if messages else None
@@ -2214,134 +1467,66 @@ def messages():
'online': is_user_online(data, other_user)
}
- html = '''
-
-
-
-
-
-
-
Messages - Content Hub
-
-
-
-
-
- ''' + NAV_HTML + '''
-
🌙
-
-
Messages
-
- {% for other_user, info in dialogs.items() %}
-
- {% if info.avatar %}
-
- {% else %}
-
- {% endif %}
-
-
{{ other_user }}
-
- {% if info.last_message %}
-
{{ info.last_message['time'] }}:
- {% if 'text' in info.last_message %}{{ info.last_message['text']|truncate(30) }}{% elif 'file' in info.last_message %}File{% elif 'post_id' in info.last_message %}Post{% endif %}
- {% endif %}
-
- {% if info.unread > 0 %}
-
{{ info.unread }}
+ html = BASE_HTML + '''
+{% block title %}Messages{% endblock %}
+{% block content %}
+
+
+
Messages
+
+ {% for other_user, info in dialogs.items() %}
+
+ {% if info.avatar %}
+
+ {% else %}
+
+ {% endif %}
+
+
{{ other_user }}
+
+ {% if info.last_message %}
+
{{ info.last_message['time'] }}:
+ {% if 'text' in info.last_message %}{{ info.last_message['text']|truncate(25) }}{% elif 'file' in info.last_message %}File{% elif 'post_id' in info.last_message %}Post{% endif %}
{% endif %}
- {% endfor %}
- {% if not dialogs %}
-
No messages yet.
- {% endif %}
-
+ {% if info.unread > 0 %}
+
{{ info.unread }}
+ {% endif %}
+
+ {% endfor %}
+ {% if not dialogs %}
+
No messages yet.
+ {% endif %}
-
-
-
+
+{% endblock %}
'''
- return render_template_string(html, dialogs=dialogs, username=username, is_authenticated=is_authenticated, repo_id=REPO_ID, unread_count=unread_count, user_count=user_count, private_unread_count=private_unread_count, is_online=is_online)
+ import base64
+ return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
+ NAV_HTML=NAV_HTML.format(**locals()), **locals())
# Приватный чат
@app.route('/chat/
', methods=['GET', 'POST'])
@@ -2362,7 +1547,6 @@ def private_chat(recipient):
user_count = len(data['users'])
is_online = is_user_online(data, username)
- # Обновляем время последнего посещения приватных чатов
data['users'][username]['last_private_visit'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
save_data(data)
@@ -2376,10 +1560,7 @@ def private_chat(recipient):
file = request.files.get('file')
post_id = request.form.get('post_id')
- message_data = {
- 'sender': username,
- 'time': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
- }
+ message_data = {'sender': username, 'time': datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
if message:
message_data['text'] = message
@@ -2389,26 +1570,7 @@ def private_chat(recipient):
temp_path = os.path.join('uploads', filename)
os.makedirs('uploads', exist_ok=True)
file.save(temp_path)
-
file_type = 'video' if filename.lower().endswith(('.mp4', '.mov', '.avi')) else 'photo'
- if filename.lower().endswith(('.heic', '.heif')):
- heif_file = pyheif.read(temp_path)
- image = Image.frombytes(
- heif_file.mode,
- heif_file.size,
- heif_file.data,
- "raw",
- heif_file.mode,
- heif_file.stride,
- )
- new_filename = filename.rsplit('.', 1)[0] + '.jpg'
- temp_new_path = os.path.join('uploads', new_filename)
- image.save(temp_new_path, "JPEG")
- os.remove(temp_path)
- temp_path = temp_new_path
- filename = new_filename
- file_type = 'photo'
-
api = HfApi()
file_path = f"chat_files/private/{chat_key}/{filename}"
api.upload_file(
@@ -2432,309 +1594,123 @@ def private_chat(recipient):
if 'text' in message_data or 'file' in message_data or 'post_id' in message_data:
data['private_chats'][chat_key].append(message_data)
save_data(data)
-
return redirect(url_for('private_chat', recipient=recipient))
recipient_avatar = data['users'][recipient].get('avatar')
recipient_online = is_user_online(data, recipient)
avatar = data['users'][username].get('avatar') if is_authenticated else None
- html = '''
-
-
-
-
-
-
- Chat with {{ recipient }} - Content Hub
-
-
-
-
-
- ''' + NAV_HTML + '''
- 🌙
-
-
- {% if recipient_avatar %}
-
- {% else %}
-
- {% endif %}
- Chat with {{ recipient }}
-
-
- {% for message in private_messages %}
-
- {% if message['sender'] == username %}
- {% if avatar %}
-
- {% else %}
-
- {% endif %}
+ html = BASE_HTML + '''
+{% block title %}Chat with {{ recipient }}{% endblock %}
+{% block content %}
+
+
+
+ {% if recipient_avatar %}
+
+ {% else %}
+
+ {% endif %}
+ Chat with {{ recipient }}
+
+
+ {% for message in private_messages %}
+
+ {% if message['sender'] == username %}
+ {% if avatar %}
+
{% else %}
- {% if recipient_avatar %}
-
+
+ {% endif %}
+ {% else %}
+ {% if recipient_avatar %}
+
+ {% else %}
+
+ {% endif %}
+ {% endif %}
+
+
{{ message['sender'] }}
+
+ {% if 'text' in message %}
{{ message['text'] }}
{% endif %}
+ {% if 'file' in message %}
+ {% if message['file_type'] == 'video' %}
+
+
+
{% else %}
-
+
{% endif %}
{% endif %}
-
-
{{ message['sender'] }}
-
- {% if 'text' in message %}
-
{{ message['text'] }}
- {% endif %}
- {% if 'file' in message %}
- {% if message['file_type'] == 'video' %}
-
-
-
- {% else %}
-
+ {% if 'post_id' in message %}
+ {% with post = posts|selectattr('id', 'equalto', message['post_id'])|first %}
+ {% if post %}
+
Shared: {{ post['title'] }}
{% endif %}
- {% endif %}
- {% if 'post_id' in message %}
- {% with post = posts|selectattr('id', 'equalto', message['post_id'])|first %}
- {% if post %}
-
Shared: {{ post['title'] }}
- {% endif %}
- {% endwith %}
- {% endif %}
-
{{ message['time'] }}
-
+ {% endwith %}
+ {% endif %}
+
{{ message['time'] }}
- {% endfor %}
-
-
-
-
-
- Share a post (optional)
- {% for post in user_posts %}
- {{ post['title'] }}
- {% endfor %}
-
- Send
-
-
Back to Messages
-
-
-
+
+ {% endfor %}
-
-
-
+
+
+
+
+ Share a post (optional)
+ {% for post in user_posts %}
+ {{ post['title'] }}
+ {% endfor %}
+
+ Send
+
+
Back to Messages
+
+{% block scripts %}
+
+{% endblock %}
+{% endblock %}
'''
user_posts = [p for p in data['posts'] if p['uploader'] == username]
- return render_template_string(html,
- private_messages=private_messages,
- recipient=recipient,
- username=username,
- is_authenticated=is_authenticated,
- repo_id=REPO_ID,
- posts=data['posts'],
- user_posts=user_posts,
- 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),
- avatar=avatar,
- recipient_avatar=recipient_avatar,
- recipient_online=recipient_online)
+ import base64
+ return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
+ NAV_HTML=NAV_HTML.format(**locals()), posts=data['posts'], user_posts=user_posts,
+ is_user_online=lambda u: is_user_online(data, u), **locals())
# Админ-панель
@app.route('/admhosto', methods=['GET', 'POST'])
@@ -2761,182 +1737,91 @@ def admin_panel():
save_data(data)
return redirect(url_for('admin_panel'))
- html = '''
-
-
-
-
-
-
-
Admin Panel - Content Hub
-
-
-
-
-
- ''' + NAV_HTML + '''
-
🌙
-
-
Admin Panel: All Posts
-
-
-
- 🔍
-
-
-
- {% if posts %}
- {% for post in posts %}
-
- {% endfor %}
- {% else %}
-
No posts found.
- {% endif %}
-
+ html = BASE_HTML + '''
+{% block title %}Admin Panel{% endblock %}
+{% block content %}
+
+
+
Admin Panel: All Posts
+
+
+
+ 🔍
+
-
-
+
+ {% if posts %}
+ {% for post in posts %}
+
+ {% endfor %}
+ {% else %}
+
No posts found.
+ {% endif %}
-
-
-
+
+{% block scripts %}
+
+{% endblock %}
+{% endblock %}
'''
- 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))
+ import base64
+ return render_template_string(html, CRITICAL_CSS=CRITICAL_CSS, FULL_CSS_BASE64=base64.b64encode(FULL_CSS.encode()).decode(),
+ NAV_HTML=NAV_HTML.format(**locals()), is_user_online=lambda u: is_user_online(data, u), **locals())
if __name__ == '__main__':
backup_thread = threading.Thread(target=periodic_backup, daemon=True)
{{ comment['user'] }} ({{ comment['date'] }}): {{ comment['text'] }}
-