diff --git "a/Codetxt.txt" "b/Codetxt.txt"
new file mode 100644--- /dev/null
+++ "b/Codetxt.txt"
@@ -0,0 +1,3216 @@
+from flask import Flask, render_template_string, request, redirect, url_for, session, flash, jsonify
+from flask_caching import Cache
+import json
+import os
+import logging
+import threading
+import time
+from datetime import datetime, timedelta
+from huggingface_hub import HfApi, hf_hub_download
+from werkzeug.utils import secure_filename
+import random
+
+app = Flask(__name__)
+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_READ = os.getenv("HF_TOKEN_READ") or HF_TOKEN_WRITE
+
+cache = Cache(app, config={'CACHE_TYPE': 'simple'})
+logging.basicConfig(level=logging.INFO)
+
+@cache.memoize(timeout=300)
+def load_data():
+ try:
+ download_db_from_hf()
+ with open(DATA_FILE, 'r', encoding='utf-8') as file:
+ data = json.load(file)
+ if not isinstance(data, dict):
+ logging.warning("Данные не в формате dict, инициализация пустой базы")
+ return {'posts': [], 'users': {}, 'general_chat': [], 'private_chats': {}}
+ data.setdefault('posts', [])
+ data.setdefault('users', {})
+ data.setdefault('general_chat', [])
+ data.setdefault('private_chats', {})
+ for user in data['users']:
+ 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:
+ logging.error(f"Ошибка при загрузке данных: {e}")
+ return {'posts': [], 'users': {}, 'general_chat': [], 'private_chats': {}}
+
+def save_data(data):
+ try:
+ 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}")
+ raise
+
+def upload_db_to_hf():
+ try:
+ api = HfApi()
+ api.upload_file(
+ path_or_fileobj=DATA_FILE,
+ path_in_repo=DATA_FILE,
+ repo_id=REPO_ID,
+ repo_type="dataset",
+ token=HF_TOKEN_WRITE,
+ commit_message=f"Бэкап {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
+ )
+ logging.info("База данных загружена на Hugging Face")
+ except Exception as e:
+ logging.error(f"Ошибка при загрузке базы данных: {e}")
+
+def download_db_from_hf():
+ try:
+ hf_hub_download(
+ repo_id=REPO_ID,
+ filename=DATA_FILE,
+ repo_type="dataset",
+ token=HF_TOKEN_READ,
+ local_dir=".",
+ local_dir_use_symlinks=False
+ )
+ logging.info("База данных скачана с Hugging Face")
+ except Exception as e:
+ logging.error(f"Ошибка при скачивании базы данных: {e}")
+ if not os.path.exists(DATA_FILE):
+ with open(DATA_FILE, 'w', encoding='utf-8') as f:
+ json.dump({'posts': [], 'users': {}, 'general_chat': [], 'private_chats': {}}, f)
+
+def periodic_backup():
+ while True:
+ upload_db_to_hf()
+ time.sleep(1800)
+
+def get_unread_count(data, username):
+ if username not in data['users']:
+ return 0
+ last_visit = datetime.strptime(data['users'][username]['last_chat_visit'], '%Y-%m-%d %H:%M:%S')
+ return sum(1 for msg in data['general_chat'] if datetime.strptime(msg['time'], '%Y-%m-%d %H:%M:%S') > last_visit)
+
+def get_private_unread_count(data, username):
+ if username not in data['users']:
+ return 0
+ last_visit = datetime.strptime(data['users'][username]['last_private_visit'], '%Y-%m-%d %H:%M:%S')
+ unread = 0
+ for chat_key, messages in data['private_chats'].items():
+ users = chat_key.split('_')
+ if username in users:
+ unread += sum(1 for msg in messages if datetime.strptime(msg['time'], '%Y-%m-%d %H:%M:%S') > last_visit and msg['sender'] != username)
+ return unread
+
+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
+
+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 = '''
+:root {
+ --primary: #ff4d6d;
+ --secondary: #00ddeb;
+ --accent: #8b5cf6;
+ --background-light: #f5f6fa;
+ --background-dark: #1a1625;
+ --card-bg: rgba(255, 255, 255, 0.95);
+ --card-bg-dark: rgba(40, 35, 60, 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.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.6;
+ overflow-x: hidden;
+}
+body.dark {
+ background: var(--background-dark);
+ color: var(--text-dark);
+}
+.sidebar {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 300px;
+ height: 100%;
+ background: var(--glass-bg);
+ backdrop-filter: blur(20px);
+ padding: 25px;
+ box-shadow: var(--shadow);
+ z-index: 1000;
+ transition: transform var(--transition);
+}
+.sidebar.hidden {
+ transform: translateX(-100%);
+}
+.sidebar-header {
+ display: flex;
+ align-items: center;
+ gap: 15px;
+ margin-bottom: 35px;
+}
+.nav-brand {
+ font-size: 1.8em;
+ font-weight: 900;
+ background: linear-gradient(135deg, var(--primary), var(--accent));
+ -webkit-background-clip: text;
+ color: transparent;
+}
+.logo {
+ width: 40px;
+ height: 40px;
+ border-radius: 14px;
+ box-shadow: var(--shadow);
+}
+.nav-links {
+ display: flex;
+ flex-direction: column;
+ gap: 15px;
+}
+.nav-link {
+ display: flex;
+ align-items: center;
+ gap: 15px;
+ padding: 14px 25px;
+ background: var(--card-bg);
+ color: var(--text-light);
+ text-decoration: none;
+ border-radius: 14px;
+ font-size: 1.1em;
+ font-weight: 600;
+ transition: var(--transition);
+ position: relative;
+}
+body.dark .nav-link {
+ background: var(--card-bg-dark);
+ color: var(--text-dark);
+}
+.nav-link:hover {
+ transform: translateX(5px);
+ background: var(--primary);
+ color: white;
+ box-shadow: 0 6px 20px rgba(255, 77, 109, 0.4);
+}
+.nav-link .badge {
+ position: absolute;
+ right: 15px;
+ background: var(--secondary);
+ color: white;
+ padding: 4px 10px;
+ border-radius: 12px;
+ font-size: 0.8em;
+ font-weight: 700;
+}
+.logout-btn {
+ background: var(--secondary);
+ color: white;
+}
+.logout-btn:hover {
+ background: #00b8c5;
+}
+.menu-btn {
+ display: none;
+ font-size: 28px;
+ 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: 20px auto 20px 320px;
+ max-width: 1200px;
+ padding: 25px;
+ transition: var(--transition);
+}
+.btn {
+ padding: 14px 28px;
+ background: var(--primary);
+ color: white;
+ border: none;
+ border-radius: 14px;
+ cursor: pointer;
+ font-size: 1.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);
+ background: #e6415f;
+ box-shadow: 0 8px 25px rgba(255, 77, 109, 0.5);
+}
+input, textarea, select {
+ width: 100%;
+ padding: 14px;
+ margin: 12px 0;
+ border: none;
+ border-radius: 14px;
+ background: var(--glass-bg);
+ color: var(--text-light);
+ font-size: 1.1em;
+ transition: var(--transition);
+ box-shadow: inset 0 3px 10px rgba(0, 0, 0, 0.1);
+}
+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);
+}
+.modal {
+ display: none;
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: rgba(0, 0, 0, 0.85);
+ z-index: 2000;
+ justify-content: center;
+ align-items: center;
+ transition: opacity var(--transition);
+}
+.modal img, .modal video {
+ max-width: 95%;
+ max-height: 95%;
+ object-fit: contain;
+ border-radius: 20px;
+ box-shadow: var(--shadow);
+ animation: zoomIn 0.3s ease;
+}
+.theme-toggle {
+ position: fixed;
+ top: 20px;
+ right: 20px;
+ background: var(--glass-bg);
+ border: none;
+ padding: 12px;
+ border-radius: 50%;
+ cursor: pointer;
+ font-size: 24px;
+ box-shadow: var(--shadow);
+ transition: var(--transition);
+}
+.theme-toggle:hover {
+ transform: rotate(90deg);
+ background: var(--accent);
+ color: white;
+}
+.status-dot {
+ width: 10px;
+ height: 10px;
+ border-radius: 50%;
+ display: inline-block;
+ margin-left: 8px;
+}
+.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) {
+ .sidebar {
+ width: 100%;
+ max-width: 300px;
+ transform: translateX(-100%);
+ }
+ .sidebar.active {
+ transform: translateX(0);
+ }
+ .menu-btn {
+ display: block;
+ }
+ .container {
+ margin: 80px 20px 20px 20px;
+ max-width: calc(100% - 40px);
+ }
+ .theme-toggle {
+ top: 80px;
+ }
+}
+@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; }
+}
+'''
+
+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 = '''
+
+
+
+
+
+
+
+ Register - Content Hub
+
+
+
+
+
+ ''' + NAV_HTML + '''
+
+
+
Register
+ {% with messages = get_flashed_messages() %}
+ {% if messages %}
+ {% for message in messages %}
+
{{ message }}
+ {% endfor %}
+ {% endif %}
+ {% endwith %}
+
+
Already have an account? Login
+
+
+
+
+'''
+ 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'])
+def login():
+ data = load_data()
+ 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
+ update_last_seen(data, username)
+ return redirect(url_for('feed'))
+ flash('Неверное имя пользователя или пароль!')
+ return redirect(url_for('login'))
+
+ is_authenticated = 'username' in session
+ username = session.get('username', None)
+ if is_authenticated:
+ update_last_seen(data, username)
+ 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 = '''
+
+
+
+
+
+
+ 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, 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')
+def logout():
+ data = load_data()
+ username = session.get('username', None)
+ if username:
+ update_last_seen(data, username)
+ session.pop('username', None)
+ return redirect(url_for('feed'))
+
+@app.route('/toggle_like/', methods=['POST'])
+def toggle_like(post_id):
+ if 'username' not in session:
+ return jsonify({'error': 'Not authenticated'}), 401
+ data = load_data()
+ username = session['username']
+ post = next((p for p in data['posts'] if p['id'] == post_id), None)
+ if not post:
+ return jsonify({'error': 'Post not found'}), 404
+
+ likes = post.get('likes', [])
+ if username in likes:
+ post['likes'] = [u for u in likes if u != username]
+ liked = False
+ else:
+ post['likes'] = likes + [username]
+ liked = True
+ save_data(data)
+ return jsonify({'liked': liked, 'likes_count': len(post['likes'])})
+
+@app.route('/increment_view/', methods=['POST'])
+def increment_view(post_id):
+ data = load_data()
+ post = next((p for p in data['posts'] if p['id'] == post_id), None)
+ if post:
+ post['views'] = post.get('views', 0) + 1
+ save_data(data)
+ return jsonify({'views': post['views']})
+ return jsonify({'error': 'Post not found'}), 404
+
+@app.route('/', methods=['GET', 'POST'])
+def feed():
+ data = load_data()
+ 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)
+ 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
+
+ if request.method == 'POST' and is_authenticated:
+ post_id = request.form.get('post_id')
+ post = next((p for p in data['posts'] if p['id'] == post_id), None)
+ if not post:
+ return "Пост не найден", 404
+
+ if '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')
+ }]
+ elif 'share' in request.form:
+ share_to = request.form.get('share_to')
+ if share_to == 'chat':
+ data['general_chat'].append({
+ 'sender': username,
+ 'time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
+ 'post_id': post_id
+ })
+ elif share_to in data['users']:
+ chat_key = f"{min(username, share_to)}_{max(username, share_to)}"
+ if chat_key not in data['private_chats']:
+ data['private_chats'][chat_key] = []
+ data['private_chats'][chat_key].append({
+ 'sender': username,
+ 'time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
+ 'post_id': post_id
+ })
+ save_data(data)
+ return redirect(url_for('feed'))
+
+ html = '''
+
+
+
+
+
+
+
+ Adusis - QoS, BBC, BNWO HUB
+
+
+
+
+
+ ''' + NAV_HTML + '''
+
+
+ {% for post in posts %}
+
+ {% if post['type'] == 'video' %}
+
+ {% else %}
+
![{{ post['title'] }}](https://huggingface.co/datasets/{{ repo_id }}/resolve/main/{{ post['type'] }}s/{{ post['filename'] }})
+ {% endif %}
+
+
{{ post['title'] }}
+
{{ post['description']|truncate(150) }}
+
By: {{ post['uploader'] }}
+
+
+
+ {{ post['likes']|length }}
+
+ {{ post['comments']|length }}
+
+ {{ post['views'] }}
+
+
+
+ {% if is_authenticated %}
+
+ {% for user in data['users']|sort %}
+ {% if user != username %}
+
+ {% endif %}
+ {% endfor %}
+ {% endif %}
+
+
+
+ {% endfor %}
+
+
+
+
+'''
+ return render_template_string(html,
+ posts=posts,
+ is_authenticated=is_authenticated,
+ username=username,
+ repo_id=REPO_ID,
+ 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),
+ data=data)
+
+@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 '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)
+ user_count = len(data['users'])
+ is_online = is_user_online(data, username)
+
+ total_views = sum(post.get('views', 0) for post in user_posts)
+ total_likes = sum(len(post.get('likes', [])) for post in user_posts)
+ user_data = data['users'].get(username, {})
+ bio = user_data.get('bio', '')
+ link = user_data.get('link', '')
+ avatar = user_data.get('avatar', None)
+ last_seen = user_data.get('last_seen', 'Never')
+
+ if request.method == 'POST':
+ if 'delete_post' in request.form:
+ post_id = request.form.get('post_id')
+ if post_id:
+ data['posts'] = [p for p in data['posts'] if p['id'] != post_id or p['uploader'] != username]
+ save_data(data)
+ return redirect(url_for('profile'))
+ elif 'update_profile' in request.form:
+ bio = request.form.get('bio', '')
+ link = request.form.get('link', '')
+ avatar_file = request.files.get('avatar')
+ if avatar_file and avatar_file.filename:
+ filename = secure_filename(avatar_file.filename)
+ temp_path = os.path.join('uploads', filename)
+ os.makedirs('uploads', exist_ok=True)
+ avatar_file.save(temp_path)
+ api = HfApi()
+ avatar_path = f"avatars/{username}/{filename}"
+ api.upload_file(
+ path_or_fileobj=temp_path,
+ path_in_repo=avatar_path,
+ repo_id=REPO_ID,
+ repo_type="dataset",
+ token=HF_TOKEN_WRITE,
+ commit_message=f"Загружен аватар для {username}"
+ )
+ data['users'][username]['avatar'] = avatar_path
+ if os.path.exists(temp_path):
+ os.remove(temp_path)
+ data['users'][username]['bio'] = bio
+ data['users'][username]['link'] = link
+ save_data(data)
+ return redirect(url_for('profile'))
+
+ html = '''
+
+
+
+
+
+
+ Profile - {{ username }} - Content Hub
+
+
+
+
+
+ ''' + NAV_HTML + '''
+
+
+
+
Edit Profile
+
+
Add Post
+
Your Posts
+
+ {% if user_posts %}
+ {% for post in user_posts %}
+
+ {% endfor %}
+ {% else %}
+
You haven't uploaded any posts yet.
+ {% endif %}
+
+
+
+
![]()
+
+
+
+
+'''
+ 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/')
+def user_profile(username):
+ data = load_data()
+ session_username = session.get('username', None)
+ if session_username:
+ update_last_seen(data, session_username)
+ if username not in data['users']:
+ return "Пользователь не найден", 404
+
+ 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, session_username) if is_authenticated else 0
+ private_unread_count = get_private_unread_count(data, session_username) if is_authenticated else 0
+ user_count = len(data['users'])
+ is_online = is_user_online(data, session_username) if is_authenticated else False
+ total_views = sum(post.get('views', 0) for post in user_posts)
+ total_likes = sum(len(post.get('likes', [])) for post in user_posts)
+ user_data = data['users'].get(username, {})
+ bio = user_data.get('bio', '')
+ link = user_data.get('link', '')
+ avatar = user_data.get('avatar', None)
+ profile_is_online = is_user_online(data, username)
+ last_seen = user_data.get('last_seen', 'Never')
+
+ html = '''
+
+
+
+
+
+
+ Profile - {{ username }} - Content Hub
+
+
+
+
+
+ ''' + NAV_HTML + '''
+
+
+
+
Posts
+
+ {% if user_posts %}
+ {% for post in user_posts %}
+
+ {% endfor %}
+ {% else %}
+
No posts yet.
+ {% endif %}
+
+
+
+
![]()
+
+
+
+
+'''
+ 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()
+ username = session['username']
+ update_last_seen(data, username)
+ is_authenticated = 'username' in session
+ unread_count = get_unread_count(data, username)
+ private_unread_count = get_private_unread_count(data, username)
+ user_count = len(data['users'])
+ is_online = is_user_online(data, username)
+
+ if request.method == 'POST':
+ title = request.form.get('title')
+ description = request.form.get('description')
+ file = request.files.get('file')
+ if not file or not title:
+ flash('Необходимо указать заголовок и выбрать файл!')
+ 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'
+ api = HfApi()
+ file_path = f"{file_type}s/{username}_{datetime.now().strftime('%Y%m%d_%H%M%S')}_{filename}"
+ api.upload_file(
+ path_or_fileobj=temp_path,
+ path_in_repo=file_path,
+ repo_id=REPO_ID,
+ repo_type="dataset",
+ token=HF_TOKEN_WRITE,
+ commit_message=f"Uploaded {file_type} by {username}"
+ )
+
+ post_id = str(random.randint(100000, 999999))
+ while any(p['id'] == post_id for p in data['posts']):
+ post_id = str(random.randint(100000, 999999))
+
+ data['posts'].append({
+ 'id': post_id,
+ 'title': title,
+ 'description': description,
+ 'filename': f"{username}_{datetime.now().strftime('%Y%m%d_%H%M%S')}_{filename}",
+ 'type': file_type,
+ 'uploader': username,
+ 'upload_date': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
+ 'views': 0,
+ 'likes': [],
+ 'comments': []
+ })
+ save_data(data)
+ if os.path.exists(temp_path):
+ os.remove(temp_path)
+ return redirect(url_for('profile'))
+
+ html = '''
+
+
+
+
+
+
+ Upload - Content Hub
+
+
+
+
+
+ ''' + NAV_HTML + '''
+
+
+
Upload Content
+ {% with messages = get_flashed_messages() %}
+ {% if messages %}
+ {% for message in messages %}
+
{{ message }}
+ {% endfor %}
+ {% endif %}
+ {% endwith %}
+
+
+
+
+
+
+'''
+ 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)
+
+@app.route('/chat', methods=['GET', 'POST'])
+def chat():
+ data = load_data()
+ username = session.get('username', None)
+ if username:
+ update_last_seen(data, username)
+ is_authenticated = 'username' in session
+ chat_messages = data['general_chat']
+
+ if is_authenticated:
+ data['users'][username]['last_chat_visit'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
+ save_data(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
+
+ if request.method == 'POST' and is_authenticated:
+ message = request.form.get('message')
+ 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')
+ }
+
+ if message:
+ message_data['text'] = message
+
+ if file and file.filename:
+ 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'
+ api = HfApi()
+ file_path = f"chat_files/general/{filename}"
+ api.upload_file(
+ path_or_fileobj=temp_path,
+ path_in_repo=file_path,
+ repo_id=REPO_ID,
+ repo_type="dataset",
+ token=HF_TOKEN_WRITE,
+ commit_message=f"Uploaded chat file by {username}"
+ )
+ message_data['file'] = file_path
+ message_data['file_type'] = file_type
+ if os.path.exists(temp_path):
+ os.remove(temp_path)
+
+ if post_id:
+ post = next((p for p in data['posts'] if p['id'] == post_id and p['uploader'] == username), None)
+ if post:
+ message_data['post_id'] = post_id
+
+ 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 %}
+
+ {% if message['sender'] == username %}
+ {% if avatar %}
+

+ {% else %}
+
+ {% endif %}
+ {% else %}
+ {% if data['users'][message['sender']].get('avatar') %}
+
![{{ message['sender'] }} Avatar](https://huggingface.co/datasets/{{ repo_id }}/resolve/main/{{ data['users'][message['sender']]['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 %}
+ {% 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'] }}
+
+
+ {% endfor %}
+
+ {% if is_authenticated %}
+
+ {% else %}
+
Login to send messages.
+ {% endif %}
+
+
+
![]()
+
+
+
+
+'''
+ user_posts = [p for p in data['posts'] if p['uploader'] == username] if is_authenticated else []
+ avatar = data['users'][username].get('avatar') if is_authenticated else None
+ 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),
+ data=data,
+ avatar=avatar)
+
+@app.route('/users', methods=['GET', 'POST'])
+def users():
+ data = load_data()
+ username = session.get('username', None)
+ if username:
+ update_last_seen(data, username)
+
+ is_authenticated = 'username' in session
+ unread_count = get_unread_count(data, username) if is_authenticated else
+ 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
+
+ search_query = request.form.get('search', '').strip().lower() if request.method == 'POST' else ''
+ user_list = [(user, data['users'][user].get('avatar'), is_user_online(data, user))
+ for user in data['users'] if not search_query or search_query in user.lower()]
+
+ html = '''
+
+
+
+
+
+
+ Users - Content Hub
+
+
+
+
+
+ ''' + NAV_HTML + '''
+
+
+
Users ({{ user_count }})
+
+
+
+
+ {% for user, avatar, online in user_list %}
+ {% if user != username %}
+
+ {% if avatar %}
+

+ {% else %}
+
+ {% endif %}
+
+
+ {% endif %}
+ {% endfor %}
+
+
+
+
+
+'''
+ 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)
+
+@app.route('/messages', methods=['GET'])
+def messages():
+ if 'username' not in session:
+ flash('Войдите, чтобы просмотреть сообщения!')
+ return redirect(url_for('login'))
+
+ data = load_data()
+ username = session['username']
+ update_last_seen(data, username)
+ is_authenticated = 'username' in session
+ unread_count = get_unread_count(data, username)
+ private_unread_count = get_private_unread_count(data, username)
+ user_count = len(data['users'])
+ is_online = is_user_online(data, username)
+
+ dialogs = {}
+ for chat_key, messages in data['private_chats'].items():
+ user1, user2 = chat_key.split('_')
+ if username not in (user1, user2):
+ continue
+ other_user = user1 if user2 == username else user2
+ last_message = messages[-1] if messages else None
+ unread = sum(1 for msg in messages if datetime.strptime(msg['time'], '%Y-%m-%d %H:%M:%S') > datetime.strptime(data['users'][username]['last_private_visit'], '%Y-%m-%d %H:%M:%S') and msg['sender'] != username)
+ dialogs[other_user] = {
+ 'last_message': last_message,
+ 'unread': unread,
+ 'avatar': data['users'][other_user].get('avatar'),
+ '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 }}
+ {% endif %}
+
+ {% endfor %}
+ {% if not dialogs %}
+
No messages yet.
+ {% endif %}
+
+
+
+
+
+'''
+ 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)
+
+@app.route('/chat/', methods=['GET', 'POST'])
+def private_chat(recipient):
+ if 'username' not in session:
+ flash('Войдите, чтобы начать чат!')
+ return redirect(url_for('login'))
+
+ data = load_data()
+ username = session['username']
+ update_last_seen(data, username)
+ if recipient not in data['users']:
+ return "Пользователь не найден", 404
+
+ is_authenticated = 'username' in session
+ unread_count = get_unread_count(data, username)
+ private_unread_count = get_private_unread_count(data, username)
+ 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)
+
+ chat_key = f"{min(username, recipient)}_{max(username, recipient)}"
+ if chat_key not in data['private_chats']:
+ data['private_chats'][chat_key] = []
+ private_messages = data['private_chats'][chat_key]
+
+ if request.method == 'POST':
+ message = request.form.get('message')
+ 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')
+ }
+
+ if message:
+ message_data['text'] = message
+
+ if file and file.filename:
+ 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'
+ api = HfApi()
+ file_path = f"chat_files/private/{chat_key}/{filename}"
+ api.upload_file(
+ path_or_fileobj=temp_path,
+ path_in_repo=file_path,
+ repo_id=REPO_ID,
+ repo_type="dataset",
+ token=HF_TOKEN_WRITE,
+ commit_message=f"Uploaded private chat file by {username} to {recipient}"
+ )
+ message_data['file'] = file_path
+ message_data['file_type'] = file_type
+ if os.path.exists(temp_path):
+ os.remove(temp_path)
+
+ if post_id:
+ post = next((p for p in data['posts'] if p['id'] == post_id and p['uploader'] == username), None)
+ if post:
+ message_data['post_id'] = post_id
+
+ 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 %}
+ {% 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 %}
+ {% 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'] }}
+
+
+ {% endfor %}
+
+
+
Back to Messages
+
+
+
![]()
+
+
+
+
+'''
+ 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)
+
+@app.route('/admhosto', methods=['GET', 'POST'])
+def admin_panel():
+ data = load_data()
+ 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)
+ 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
+
+ search_query = request.form.get('search', '').strip().lower() if request.method == 'POST' and 'search' in request.form else request.args.get('search', '').strip().lower()
+ if search_query:
+ posts = [post for post in posts if search_query in post['title'].lower() or search_query in post['description'].lower()]
+
+ if request.method == 'POST' and 'delete' in request.form:
+ post_id = request.form.get('post_id')
+ if post_id:
+ data['posts'] = [p for p in data['posts'] if p['id'] != post_id]
+ save_data(data)
+ return redirect(url_for('admin_panel'))
+
+ html = '''
+
+
+
+
+
+
+ Admin Panel - Content Hub
+
+
+
+
+
+ ''' + NAV_HTML + '''
+
+
+
+
![]()
+
+
+
+
+'''
+ return render_template_string(html,
+ posts=posts,
+ is_authenticated=is_authenticated,
+ username=username,
+ repo_id=REPO_ID,
+ 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),
+ search_query=search_query)
+
+if __name__ == '__main__':
+ threading.Thread(target=periodic_backup, daemon=True).start()
+ app.run(debug=True, host='0.0.0.0', port=7860)
\ No newline at end of file