diff --git "a/app.py" "b/app.py"
deleted file mode 100644--- "a/app.py"
+++ /dev/null
@@ -1,3102 +0,0 @@
-from flask import Flask, render_template_string, request, redirect, url_for, session, flash
-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: #fef9f1;
- --background-dark: #1f1a44;
- --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 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;
-}
-* { 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;
- transition: var(--transition);
- overflow-x: hidden;
-}
-body.dark {
- background: var(--background-dark);
- color: var(--text-dark);
-}
-.sidebar {
- position: fixed;
- top: 0;
- left: 0;
- width: 280px;
- height: 100%;
- background: var(--glass-bg);
- backdrop-filter: blur(15px);
- padding: 20px;
- box-shadow: var(--shadow);
- z-index: 1000;
- transition: transform var(--transition);
-}
-.sidebar.hidden {
- transform: translateX(-100%);
-}
-.sidebar-header {
- display: flex;
- align-items: center;
- gap: 12px;
- margin-bottom: 30px;
-}
-.nav-brand {
- font-size: 1.6em;
- font-weight: 800;
- background: linear-gradient(135deg, var(--primary), var(--accent));
- -webkit-background-clip: text;
- color: transparent;
-}
-.logo {
- width: 36px;
- height: 36px;
- border-radius: 12px;
- box-shadow: var(--shadow);
-}
-.nav-links {
- display: flex;
- flex-direction: column;
- gap: 12px;
-}
-.nav-link {
- display: flex;
- align-items: center;
- gap: 12px;
- padding: 12px 20px;
- background: var(--card-bg);
- color: var(--text-light);
- text-decoration: none;
- border-radius: 12px;
- font-size: 1em;
- font-weight: 500;
- transition: var(--transition);
- position: relative;
-}
-body.dark .nav-link {
- background: var(--card-bg-dark);
- color: var(--text-dark);
-}
-.nav-link:hover {
- transform: scale(1.02);
- background: var(--primary);
- color: white;
- box-shadow: 0 4px 16px rgba(255, 77, 109, 0.3);
-}
-.nav-link .badge {
- position: absolute;
- right: 12px;
- background: var(--secondary);
- color: white;
- 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;
- background: var(--primary);
- color: white;
- border: none;
- border-radius: 12px;
- cursor: pointer;
- 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%;
- padding: 12px;
- margin: 10px 0;
- border: none;
- border-radius: 12px;
- background: var(--glass-bg);
- 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);
-}
-input:focus, textarea:focus, select:focus {
- outline: none;
- background: rgba(255, 255, 255, 0.15);
- box-shadow: 0 0 0 3px var(--primary);
-}
-.modal {
- display: none;
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- 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: 90%;
- object-fit: contain;
- border-radius: 16px;
- box-shadow: var(--shadow);
- animation: zoomIn 0.3s ease;
-}
-.theme-toggle {
- position: fixed;
- top: 15px;
- right: 15px;
- background: var(--glass-bg);
- border: none;
- padding: 10px;
- border-radius: 50%;
- cursor: pointer;
- font-size: 20px;
- box-shadow: var(--shadow);
- transition: var(--transition);
-}
-.theme-toggle:hover {
- transform: rotate(90deg);
- background: var(--accent);
- color: white;
-}
-.status-dot {
- 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.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: 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 = '''
-
-'''
-
-@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('/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 '', 204
- return 'Пост не найден', 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 'like' in request.form:
- if username not in post.get('likes', []):
- post['likes'] = post.get('likes', []) + [username]
- else:
- post['likes'] = [u for u in post.get('likes', []) if u != username]
- 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')
- }]
- 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(100) }}
-
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 '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)
- 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 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' 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(25) }}{% 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