Eluza133 commited on
Commit
c1be53d
·
verified ·
1 Parent(s): d9f6023

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +185 -123
app.py CHANGED
@@ -85,6 +85,26 @@ def periodic_backup():
85
  upload_db_to_hf()
86
  time.sleep(15)
87
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  # Регистрация пользователя
89
  @app.route('/register', methods=['GET', 'POST'])
90
  def register():
@@ -103,6 +123,8 @@ def register():
103
  flash('Регистрация успешна! Войдите в систему.')
104
  return redirect(url_for('login'))
105
 
 
 
106
  html = '''
107
  <!DOCTYPE html>
108
  <html lang="ru">
@@ -112,18 +134,35 @@ def register():
112
  <title>Регистрация</title>
113
  <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet">
114
  <style>
115
- body { font-family: 'Poppins', sans-serif; background: #f0f2f5; padding: 20px; margin: 0; }
116
- .container { max-width: 400px; margin: 0 auto; background: #fff; padding: 20px; border-radius: 10px; box-shadow: 0 4px 15px rgba(0,0,0,0.1); }
117
- input { width: 100%; padding: 10px; margin: 10px 0; border: 1px solid #e2e8f0; border-radius: 8px; box-sizing: border-box; }
118
- button { padding: 10px 20px; background: #3b82f6; color: white; border: none; border-radius: 8px; cursor: pointer; width: 100%; }
119
- .flash { color: red; margin-bottom: 10px; }
120
- @media (max-width: 600px) {
121
- .container { padding: 15px; max-width: 100%; }
122
- input, button { font-size: 14px; padding: 8px; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
  }
124
  </style>
125
  </head>
126
  <body>
 
 
127
  <div class="container">
128
  <h1>Регистрация</h1>
129
  {% with messages = get_flashed_messages() %}
@@ -140,10 +179,15 @@ def register():
140
  </form>
141
  <p>Уже есть аккаунт? <a href="{{ url_for('login') }}">Войти</a></p>
142
  </div>
 
 
 
 
 
143
  </body>
144
  </html>
145
  '''
146
- return render_template_string(html)
147
 
148
  # Авторизация пользователя
149
  @app.route('/login', methods=['GET', 'POST'])
@@ -161,6 +205,8 @@ def login():
161
  flash('Неверный логин или пароль!')
162
  return redirect(url_for('login'))
163
 
 
 
164
  html = '''
165
  <!DOCTYPE html>
166
  <html lang="ru">
@@ -170,18 +216,35 @@ def login():
170
  <title>Вход</title>
171
  <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet">
172
  <style>
173
- body { font-family: 'Poppins', sans-serif; background: #f0f2f5; padding: 20px; margin: 0; }
174
- .container { max-width: 400px; margin: 0 auto; background: #fff; padding: 20px; border-radius: 10px; box-shadow: 0 4px 15px rgba(0,0,0,0.1); }
175
- input { width: 100%; padding: 10px; margin: 10px 0; border: 1px solid #e2e8f0; border-radius: 8px; box-sizing: border-box; }
176
- button { padding: 10px 20px; background: #3b82f6; color: white; border: none; border-radius: 8px; cursor: pointer; width: 100%; }
177
- .flash { color: red; margin-bottom: 10px; }
178
- @media (max-width: 600px) {
179
- .container { padding: 15px; max-width: 100%; }
180
- input, button { font-size: 14px; padding: 8px; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
181
  }
182
  </style>
183
  </head>
184
  <body>
 
 
185
  <div class="container">
186
  <h1>Вход</h1>
187
  {% with messages = get_flashed_messages() %}
@@ -198,10 +261,15 @@ def login():
198
  </form>
199
  <p>Нет аккаунта? <a href="{{ url_for('register') }}">Зарегистрироваться</a></p>
200
  </div>
 
 
 
 
 
201
  </body>
202
  </html>
203
  '''
204
- return render_template_string(html)
205
 
206
  # Выход из системы
207
  @app.route('/logout')
@@ -223,46 +291,40 @@ def feed():
223
  <head>
224
  <meta charset="UTF-8">
225
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
226
- <title>Хостинг контента</title>
227
  <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet">
228
  <style>
229
- body { font-family: 'Poppins', sans-serif; background: #f0f2f5; padding: 20px; margin: 0; }
230
- .container { max-width: 1200px; margin: 0 auto; padding-left: 220px; transition: padding-left 0.3s; }
231
- .sidebar { position: fixed; left: -220px; top: 0; width: 200px; height: 100%; background: #fff; padding: 20px; box-shadow: 2px 0 5px rgba(0,0,0,0.1); transition: left 0.3s; z-index: 1000; }
232
- .sidebar.active { left: 0; }
 
 
 
 
 
 
 
233
  .post-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 20px; }
234
- .post-item { background: #fff; padding: 15px; border-radius: 10px; box-shadow: 0 4px 15px rgba(0,0,0,0.1); text-decoration: none; color: #2d3748; }
 
235
  .post-preview { width: 100%; border-radius: 8px; height: 200px; object-fit: cover; }
236
- .auth-links, .upload-btn, .logout-btn, .profile-link { display: block; margin: 10px 0; padding: 10px; background: #3b82f6; color: white; text-align: center; text-decoration: none; border-radius: 8px; }
237
- .logout-btn { background: #ef4444; }
238
- .profile-link { background: #10b981; }
239
- .menu-btn { display: none; font-size: 24px; background: none; border: none; cursor: pointer; position: fixed; top: 20px; left: 20px; z-index: 1001; }
240
- .stats { font-size: 0.9em; color: #666; }
241
  @media (max-width: 768px) {
242
- .container { padding-left: 20px; padding: 10px; }
243
- .sidebar { left: -220px; width: 150px; padding: 15px; }
244
- .sidebar.active { left: 0; }
245
  .menu-btn { display: block; }
 
246
  .post-grid { grid-template-columns: 1fr; gap: 15px; }
247
  .post-item { padding: 10px; }
248
  .post-preview { height: 150px; }
249
- .auth-links, .upload-btn, .logout-btn, .profile-link { font-size: 14px; padding: 8px; }
250
  }
251
  </style>
252
  </head>
253
  <body>
254
  <button class="menu-btn" onclick="toggleSidebar()">☰</button>
255
- <div class="sidebar" id="sidebar">
256
- {% if is_authenticated %}
257
- <a href="{{ url_for('profile') }}" class="profile-link">
258
- <span style="font-size: 1.2em;">👤</span> {{ username }}
259
- </a>
260
- <a href="{{ url_for('logout') }}" class="logout-btn">Выйти</a>
261
- {% else %}
262
- <a href="{{ url_for('login') }}" class="auth-links">Войти</a>
263
- <a href="{{ url_for('register') }}" class="auth-links">Зарегистрироваться</a>
264
- {% endif %}
265
- </div>
266
  <div class="container">
267
  <h1>Лента публикаций</h1>
268
  <div class="post-grid">
@@ -342,42 +404,39 @@ def post_page(post_id):
342
  <title>{{ post['title'] }}</title>
343
  <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet">
344
  <style>
345
- body { font-family: 'Poppins', sans-serif; background: #f0f2f5; padding: 20px; margin: 0; }
346
- .sidebar { position: fixed; left: -220px; top: 0; width: 200px; height: 100%; background: #fff; padding: 20px; box-shadow: 2px 0 5px rgba(0,0,0,0.1); transition: left 0.3s; z-index: 1000; }
347
- .sidebar.active { left: 0; }
348
- .container { max-width: 800px; margin: 0 auto; padding-left: 220px; background: #fff; padding: 20px; border-radius: 10px; box-shadow: 0 4px 15px rgba(0,0,0,0.1); transition: padding-left 0.3s; }
 
 
 
 
 
 
 
349
  video, img { width: 100%; border-radius: 8px; max-height: 400px; object-fit: cover; }
350
- .back-btn, .profile-link, .logout-btn, .like-btn { display: inline-block; margin: 10px 0; padding: 10px; background: #3b82f6; color: white; text-decoration: none; border-radius: 8px; border: none; cursor: pointer; }
351
- .profile-link { background: #10b981; }
352
- .logout-btn { background: #ef4444; }
353
- .like-btn.liked { background: #ef4444; }
354
- .menu-btn { display: none; font-size: 24px; background: none; border: none; cursor: pointer; position: fixed; top: 20px; left: 20px; z-index: 1001; }
355
- textarea { width: 100%; padding: 10px; margin: 10px 0; border: 1px solid #e2e8f0; border-radius: 8px; }
356
  .comment { border-top: 1px solid #e2e8f0; padding: 10px 0; }
357
  @media (max-width: 768px) {
358
- .container { padding-left: 20px; padding: 15px; max-width: 100%; }
359
- .sidebar { left: -220px; width: 150px; padding: 15px; }
360
- .sidebar.active { left: 0; }
361
  .menu-btn { display: block; }
 
362
  video, img { max-height: 250px; }
363
- .back-btn, .like-btn, textarea, button { width: 100%; font-size: 14px; padding: 8px; margin: 5px 0; }
364
- h1 { font-size: 1.2em; }
 
365
  }
366
  </style>
367
  </head>
368
  <body>
369
  <button class="menu-btn" onclick="toggleSidebar()">☰</button>
370
- <div class="sidebar" id="sidebar">
371
- {% if is_authenticated %}
372
- <a href="{{ url_for('profile') }}" class="profile-link">
373
- <span style="font-size: 1.2em;">👤</span> {{ username }}
374
- </a>
375
- <a href="{{ url_for('logout') }}" class="logout-btn">Выйти</a>
376
- {% else %}
377
- <a href="{{ url_for('login') }}" class="profile-link">Войти</a>
378
- <a href="{{ url_for('register') }}" class="profile-link">Зарегистрироваться</a>
379
- {% endif %}
380
- </div>
381
  <div class="container">
382
  <h1>{{ post['title'] }}</h1>
383
  {% if post['type'] == 'video' %}
@@ -391,14 +450,14 @@ def post_page(post_id):
391
  <p>Загрузил: {{ post['uploader'] }} | {{ post['upload_date'] }}</p>
392
  <p>Просмотров: {{ post['views'] }} | Лайков: {{ post['likes']|length }}</p>
393
  {% if is_authenticated %}
394
- <form method="POST">
395
- <button type="submit" name="like" class="like-btn {% if username in post['likes'] %}liked{% endif %}">
396
  {% if username in post['likes'] %}Убрать лайк{% else %}Лайк{% endif %}
397
  </button>
398
  </form>
399
  <form method="POST">
400
  <textarea name="comment" placeholder="Оставьте комментарий" rows="3"></textarea>
401
- <button type="submit">Отправить</button>
402
  </form>
403
  {% endif %}
404
  <h3>Комментарии</h3>
@@ -407,7 +466,7 @@ def post_page(post_id):
407
  <p><strong>{{ comment['user'] }}</strong> ({{ comment['date'] }}): {{ comment['text'] }}</p>
408
  </div>
409
  {% endfor %}
410
- <a href="{{ url_for('feed') }}" class="back-btn">Назад к ленте</a>
411
  {% if not is_authenticated %}
412
  <p><a href="{{ url_for('login') }}">Войдите</a>, чтобы ставить лайки и комментировать.</p>
413
  {% endif %}
@@ -432,6 +491,7 @@ def profile():
432
  data = load_data()
433
  username = session['username']
434
  user_posts = [p for p in data['posts'] if p['uploader'] == username]
 
435
 
436
  if request.method == 'POST':
437
  post_id = request.form.get('post_id')
@@ -450,43 +510,45 @@ def profile():
450
  <title>Профиль - {{ username }}</title>
451
  <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet">
452
  <style>
453
- body { font-family: 'Poppins', sans-serif; background: #f0f2f5; padding: 20px; margin: 0; }
454
- .sidebar { position: fixed; left: -220px; top: 0; width: 200px; height: 100%; background: #fff; padding: 20px; box-shadow: 2px 0 5px rgba(0,0,0,0.1); transition: left 0.3s; z-index: 1000; }
455
- .sidebar.active { left: 0; }
456
- .container { max-width: 800px; margin: 0 auto; padding-left: 220px; transition: padding-left 0.3s; }
 
 
 
 
 
 
 
457
  .post-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 20px; }
458
- .post-item { background: #fff; padding: 15px; border-radius: 10px; box-shadow: 0 4px 15px rgba(0,0,0,0.1); }
 
459
  .post-preview { width: 100%; border-radius: 8px; height: 200px; object-fit: cover; }
460
- .upload-btn, .delete-btn, .profile-link, .logout-btn { display: block; margin: 10px 0; padding: 10px; background: #3b82f6; color: white; text-decoration: none; border-radius: 8px; }
461
- .delete-btn { background: #ef4444; border: none; cursor: pointer; }
462
- .profile-link { background: #10b981; }
463
- .logout-btn { background: #ef4444; }
464
- .menu-btn { display: none; font-size: 24px; background: none; border: none; cursor: pointer; position: fixed; top: 20px; left: 20px; z-index: 1001; }
465
- .stats { font-size: 0.9em; color: #666; }
466
  @media (max-width: 768px) {
467
- .container { padding-left: 20px; padding: 15px; max-width: 100%; }
468
- .sidebar { left: -220px; width: 150px; padding: 15px; }
469
- .sidebar.active { left: 0; }
470
  .menu-btn { display: block; }
 
471
  .post-grid { grid-template-columns: 1fr; gap: 15px; }
472
  .post-item { padding: 10px; }
473
  .post-preview { height: 150px; }
474
- .upload-btn, .delete-btn, .profile-link, .logout-btn { font-size: 14px; padding: 8px; }
475
- h1, h2 { font-size: 1.2em; }
476
  }
477
  </style>
478
  </head>
479
  <body>
480
  <button class="menu-btn" onclick="toggleSidebar()">☰</button>
481
- <div class="sidebar" id="sidebar">
482
- <a href="{{ url_for('profile') }}" class="profile-link">
483
- <span style="font-size: 1.2em;">👤</span> {{ username }}
484
- </a>
485
- <a href="{{ url_for('logout') }}" class="logout-btn">Выйти</a>
486
- </div>
487
  <div class="container">
488
  <h1>Профиль: {{ username }}</h1>
489
- <a href="{{ url_for('upload') }}" class="upload-btn">Добавить публикацию</a>
490
  <h2>Ваши публикации</h2>
491
  <div class="post-grid">
492
  {% if user_posts %}
@@ -507,7 +569,7 @@ def profile():
507
  <p class="stats">Просмотров: {{ post['views'] }} | Лайков: {{ post['likes']|length }}</p>
508
  <form method="POST">
509
  <input type="hidden" name="post_id" value="{{ post['id'] }}">
510
- <button type="submit" class="delete-btn">Удалить</button>
511
  </form>
512
  </div>
513
  {% endfor %}
@@ -536,7 +598,7 @@ def profile():
536
  </body>
537
  </html>
538
  '''
539
- return render_template_string(html, username=username, user_posts=user_posts, repo_id=REPO_ID)
540
 
541
  # Страница загрузки контента
542
  @app.route('/upload', methods=['GET', 'POST'])
@@ -598,7 +660,8 @@ def upload():
598
 
599
  return redirect(url_for('profile'))
600
 
601
- username = session['username']
 
602
  html = '''
603
  <!DOCTYPE html>
604
  <html lang="ru">
@@ -608,25 +671,29 @@ def upload():
608
  <title>Загрузка контента</title>
609
  <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet">
610
  <style>
611
- body { font-family: 'Poppins', sans-serif; background: #f0f2f5; padding: 20px; margin: 0; }
612
- .sidebar { position: fixed; left: -220px; top: 0; width: 200px; height: 100%; background: #fff; padding: 20px; box-shadow: 2px 0 5px rgba(0,0,0,0.1); transition: left 0.3s; z-index: 1000; }
613
- .sidebar.active { left: 0; }
614
- .container { max-width: 600px; margin: 0 auto; padding-left: 220px; background: #fff; padding: 20px; border-radius: 10px; box-shadow: 0 4px 15px rgba(0,0,0,0.1); transition: padding-left 0.3s; }
615
- input, textarea { width: 100%; padding: 10px; margin: 10px 0; border: 1px solid #e2e8f0; border-radius: 8px; box-sizing: border-box; }
616
- button { padding: 10px 20px; background: #3b82f6; color: white; border: none; border-radius: 8px; cursor: pointer; width: 100%; }
 
 
 
 
 
 
 
 
617
  #progress-container { margin-top: 10px; }
618
- #progress-bar { width: 0%; height: 20px; background: #3b82f6; border-radius: 8px; transition: width 0.3s; }
619
- .profile-link, .logout-btn { display: block; margin: 10px 0; padding: 10px; background: #3b82f6; color: white; text-decoration: none; border-radius: 8px; }
620
- .profile-link { background: #10b981; }
621
- .logout-btn { background: #ef4444; }
622
- .menu-btn { display: none; font-size: 24px; background: none; border: none; cursor: pointer; position: fixed; top: 20px; left: 20px; z-index: 1001; }
623
  @media (max-width: 768px) {
624
- .container { padding-left: 20px; padding: 15px; max-width: 100%; }
625
- .sidebar { left: -220px; width: 150px; padding: 15px; }
626
- .sidebar.active { left: 0; }
627
  .menu-btn { display: block; }
628
- input, textarea, button { font-size: 14px; padding: 8px; margin: 5px 0; }
629
- h1 { font-size: 1.2em; }
 
630
  #progress-container { height: 15px; }
631
  #progress-bar { height: 15px; }
632
  }
@@ -634,12 +701,7 @@ def upload():
634
  </head>
635
  <body>
636
  <button class="menu-btn" onclick="toggleSidebar()">☰</button>
637
- <div class="sidebar" id="sidebar">
638
- <a href="{{ url_for('profile') }}" class="profile-link">
639
- <span style="font-size: 1.2em;">👤</span> {{ username }}
640
- </a>
641
- <a href="{{ url_for('logout') }}" class="logout-btn">Выйти</a>
642
- </div>
643
  <div class="container">
644
  <h1>Загрузить контент</h1>
645
  <form id="upload-form" enctype="multipart/form-data">
@@ -689,7 +751,7 @@ def upload():
689
  </body>
690
  </html>
691
  '''
692
- return render_template_string(html, username=username)
693
 
694
  if __name__ == '__main__':
695
  backup_thread = threading.Thread(target=periodic_backup, daemon=True)
 
85
  upload_db_to_hf()
86
  time.sleep(15)
87
 
88
+ # Базовый шаблон боковой навигации
89
+ NAV_HTML = '''
90
+ <aside class="sidebar" id="sidebar">
91
+ <div class="sidebar-header">
92
+ <span class="nav-brand">Контент Хост</span>
93
+ </div>
94
+ <nav class="nav-links">
95
+ <a href="{{ url_for('feed') }}" class="nav-link"><span>📜</span> Лента</a>
96
+ {% if is_authenticated %}
97
+ <a href="{{ url_for('profile') }}" class="nav-link"><span>👤</span> Профиль ({{ username }})</a>
98
+ <a href="{{ url_for('upload') }}" class="nav-link"><span>⬆️</span> Загрузить</a>
99
+ <a href="{{ url_for('logout') }}" class="nav-link logout-btn"><span>🚪</span> Выйти</a>
100
+ {% else %}
101
+ <a href="{{ url_for('login') }}" class="nav-link"><span>🔑</span> Войти</a>
102
+ <a href="{{ url_for('register') }}" class="nav-link"><span>✨</span> Регистрация</a>
103
+ {% endif %}
104
+ </nav>
105
+ </aside>
106
+ '''
107
+
108
  # Регистрация пользователя
109
  @app.route('/register', methods=['GET', 'POST'])
110
  def register():
 
123
  flash('Регистрация успешна! Войдите в систему.')
124
  return redirect(url_for('login'))
125
 
126
+ is_authenticated = 'username' in session
127
+ username = session.get('username', None)
128
  html = '''
129
  <!DOCTYPE html>
130
  <html lang="ru">
 
134
  <title>Регистрация</title>
135
  <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet">
136
  <style>
137
+ body { font-family: 'Poppins', sans-serif; background: linear-gradient(135deg, #e0e7ff, #f3f4f6); margin: 0; padding: 0; min-height: 100vh; }
138
+ .sidebar { position: fixed; left: 0; top: 0; width: 250px; height: 100%; background: rgba(255, 255, 255, 0.9); backdrop-filter: blur(10px); padding: 20px; box-shadow: 2px 0 15px rgba(0,0,0,0.1); transition: transform 0.3s ease; z-index: 1000; }
139
+ .sidebar-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; }
140
+ .nav-brand { font-size: 1.5em; font-weight: 600; color: #3b82f6; }
141
+ .nav-links { display: flex; flex-direction: column; gap: 10px; }
142
+ .nav-link { display: flex; align-items: center; gap: 10px; padding: 12px 15px; background: rgba(59, 130, 246, 0.1); color: #3b82f6; text-decoration: none; border-radius: 8px; transition: all 0.3s ease; }
143
+ .nav-link:hover { background: rgba(59, 130, 246, 0.3); color: #2563eb; transform: translateX(5px); }
144
+ .logout-btn { background: rgba(239, 68, 68, 0.1); color: #ef4444; }
145
+ .logout-btn:hover { background: rgba(239, 68, 68, 0.3); color: #dc2626; }
146
+ .menu-btn { display: none; font-size: 28px; background: rgba(255, 255, 255, 0.9); border: none; color: #3b82f6; cursor: pointer; position: fixed; top: 15px; left: 15px; z-index: 1001; padding: 5px 10px; border-radius: 5px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
147
+ .container { max-width: 400px; margin: 20px auto 20px 270px; background: rgba(255, 255, 255, 0.95); backdrop-filter: blur(5px); padding: 20px; border-radius: 12px; box-shadow: 0 4px 20px rgba(0,0,0,0.1); transition: margin-left 0.3s ease; }
148
+ input { width: 100%; padding: 12px; margin: 10px 0; border: 1px solid #e2e8f0; border-radius: 8px; box-sizing: border-box; background: rgba(255, 255, 255, 0.8); }
149
+ button { padding: 12px; background: #3b82f6; color: white; border: none; border-radius: 8px; cursor: pointer; width: 100%; transition: background 0.3s ease; }
150
+ button:hover { background: #2563eb; }
151
+ .flash { color: #ef4444; margin-bottom: 10px; text-align: center; }
152
+ @media (max-width: 768px) {
153
+ .sidebar { transform: translateX(-100%); width: 200px; }
154
+ .sidebar.active { transform: translateX(0); }
155
+ .menu-btn { display: block; }
156
+ .container { margin: 60px 10px 20px 10px; max-width: calc(100% - 20px); }
157
+ input, button { font-size: 14px; padding: 10px; }
158
+ .nav-brand { font-size: 1.2em; }
159
+ .nav-link { padding: 10px; font-size: 14px; }
160
  }
161
  </style>
162
  </head>
163
  <body>
164
+ <button class="menu-btn" onclick="toggleSidebar()">☰</button>
165
+ ''' + NAV_HTML + '''
166
  <div class="container">
167
  <h1>Регистрация</h1>
168
  {% with messages = get_flashed_messages() %}
 
179
  </form>
180
  <p>Уже есть аккаунт? <a href="{{ url_for('login') }}">Войти</a></p>
181
  </div>
182
+ <script>
183
+ function toggleSidebar() {
184
+ document.getElementById('sidebar').classList.toggle('active');
185
+ }
186
+ </script>
187
  </body>
188
  </html>
189
  '''
190
+ return render_template_string(html, is_authenticated=is_authenticated, username=username)
191
 
192
  # Авторизация пользователя
193
  @app.route('/login', methods=['GET', 'POST'])
 
205
  flash('Неверный логин или пароль!')
206
  return redirect(url_for('login'))
207
 
208
+ is_authenticated = 'username' in session
209
+ username = session.get('username', None)
210
  html = '''
211
  <!DOCTYPE html>
212
  <html lang="ru">
 
216
  <title>Вход</title>
217
  <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet">
218
  <style>
219
+ body { font-family: 'Poppins', sans-serif; background: linear-gradient(135deg, #e0e7ff, #f3f4f6); margin: 0; padding: 0; min-height: 100vh; }
220
+ .sidebar { position: fixed; left: 0; top: 0; width: 250px; height: 100%; background: rgba(255, 255, 255, 0.9); backdrop-filter: blur(10px); padding: 20px; box-shadow: 2px 0 15px rgba(0,0,0,0.1); transition: transform 0.3s ease; z-index: 1000; }
221
+ .sidebar-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; }
222
+ .nav-brand { font-size: 1.5em; font-weight: 600; color: #3b82f6; }
223
+ .nav-links { display: flex; flex-direction: column; gap: 10px; }
224
+ .nav-link { display: flex; align-items: center; gap: 10px; padding: 12px 15px; background: rgba(59, 130, 246, 0.1); color: #3b82f6; text-decoration: none; border-radius: 8px; transition: all 0.3s ease; }
225
+ .nav-link:hover { background: rgba(59, 130, 246, 0.3); color: #2563eb; transform: translateX(5px); }
226
+ .logout-btn { background: rgba(239, 68, 68, 0.1); color: #ef4444; }
227
+ .logout-btn:hover { background: rgba(239, 68, 68, 0.3); color: #dc2626; }
228
+ .menu-btn { display: none; font-size: 28px; background: rgba(255, 255, 255, 0.9); border: none; color: #3b82f6; cursor: pointer; position: fixed; top: 15px; left: 15px; z-index: 1001; padding: 5px 10px; border-radius: 5px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
229
+ .container { max-width: 400px; margin: 20px auto 20px 270px; background: rgba(255, 255, 255, 0.95); backdrop-filter: blur(5px); padding: 20px; border-radius: 12px; box-shadow: 0 4px 20px rgba(0,0,0,0.1); transition: margin-left 0.3s ease; }
230
+ input { width: 100%; padding: 12px; margin: 10px 0; border: 1px solid #e2e8f0; border-radius: 8px; box-sizing: border-box; background: rgba(255, 255, 255, 0.8); }
231
+ button { padding: 12px; background: #3b82f6; color: white; border: none; border-radius: 8px; cursor: pointer; width: 100%; transition: background 0.3s ease; }
232
+ button:hover { background: #2563eb; }
233
+ .flash { color: #ef4444; margin-bottom: 10px; text-align: center; }
234
+ @media (max-width: 768px) {
235
+ .sidebar { transform: translateX(-100%); width: 200px; }
236
+ .sidebar.active { transform: translateX(0); }
237
+ .menu-btn { display: block; }
238
+ .container { margin: 60px 10px 20px 10px; max-width: calc(100% - 20px); }
239
+ input, button { font-size: 14px; padding: 10px; }
240
+ .nav-brand { font-size: 1.2em; }
241
+ .nav-link { padding: 10px; font-size: 14px; }
242
  }
243
  </style>
244
  </head>
245
  <body>
246
+ <button class="menu-btn" onclick="toggleSidebar()">☰</button>
247
+ ''' + NAV_HTML + '''
248
  <div class="container">
249
  <h1>Вход</h1>
250
  {% with messages = get_flashed_messages() %}
 
261
  </form>
262
  <p>Нет аккаунта? <a href="{{ url_for('register') }}">Зарегистрироваться</a></p>
263
  </div>
264
+ <script>
265
+ function toggleSidebar() {
266
+ document.getElementById('sidebar').classList.toggle('active');
267
+ }
268
+ </script>
269
  </body>
270
  </html>
271
  '''
272
+ return render_template_string(html, is_authenticated=is_authenticated, username=username)
273
 
274
  # Выход из системы
275
  @app.route('/logout')
 
291
  <head>
292
  <meta charset="UTF-8">
293
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
294
+ <title>Лента</title>
295
  <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet">
296
  <style>
297
+ body { font-family: 'Poppins', sans-serif; background: linear-gradient(135deg, #e0e7ff, #f3f4f6); margin: 0; padding: 0; min-height: 100vh; }
298
+ .sidebar { position: fixed; left: 0; top: 0; width: 250px; height: 100%; background: rgba(255, 255, 255, 0.9); backdrop-filter: blur(10px); padding: 20px; box-shadow: 2px 0 15px rgba(0,0,0,0.1); transition: transform 0.3s ease; z-index: 1000; }
299
+ .sidebar-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; }
300
+ .nav-brand { font-size: 1.5em; font-weight: 600; color: #3b82f6; }
301
+ .nav-links { display: flex; flex-direction: column; gap: 10px; }
302
+ .nav-link { display: flex; align-items: center; gap: 10px; padding: 12px 15px; background: rgba(59, 130, 246, 0.1); color: #3b82f6; text-decoration: none; border-radius: 8px; transition: all 0.3s ease; }
303
+ .nav-link:hover { background: rgba(59, 130, 246, 0.3); color: #2563eb; transform: translateX(5px); }
304
+ .logout-btn { background: rgba(239, 68, 68, 0.1); color: #ef4444; }
305
+ .logout-btn:hover { background: rgba(239, 68, 68, 0.3); color: #dc2626; }
306
+ .menu-btn { display: none; font-size: 28px; background: rgba(255, 255, 255, 0.9); border: none; color: #3b82f6; cursor: pointer; position: fixed; top: 15px; left: 15px; z-index: 1001; padding: 5px 10px; border-radius: 5px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
307
+ .container { max-width: 1200px; margin: 20px auto 20px 270px; padding: 20px; transition: margin-left 0.3s ease; }
308
  .post-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 20px; }
309
+ .post-item { background: rgba(255, 255, 255, 0.95); backdrop-filter: blur(5px); padding: 15px; border-radius: 12px; box-shadow: 0 4px 20px rgba(0,0,0,0.1); text-decoration: none; color: #2d3748; transition: transform 0.3s ease; }
310
+ .post-item:hover { transform: scale(1.02); }
311
  .post-preview { width: 100%; border-radius: 8px; height: 200px; object-fit: cover; }
312
+ .stats { font-size: 0.9em; color: #666; margin-top: 5px; }
 
 
 
 
313
  @media (max-width: 768px) {
314
+ .sidebar { transform: translateX(-100%); width: 200px; }
315
+ .sidebar.active { transform: translateX(0); }
 
316
  .menu-btn { display: block; }
317
+ .container { margin: 60px 10px 20px 10px; max-width: calc(100% - 20px); }
318
  .post-grid { grid-template-columns: 1fr; gap: 15px; }
319
  .post-item { padding: 10px; }
320
  .post-preview { height: 150px; }
321
+ h1 { font-size: 1.5em; }
322
  }
323
  </style>
324
  </head>
325
  <body>
326
  <button class="menu-btn" onclick="toggleSidebar()">☰</button>
327
+ ''' + NAV_HTML + '''
 
 
 
 
 
 
 
 
 
 
328
  <div class="container">
329
  <h1>Лента публикаций</h1>
330
  <div class="post-grid">
 
404
  <title>{{ post['title'] }}</title>
405
  <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet">
406
  <style>
407
+ body { font-family: 'Poppins', sans-serif; background: linear-gradient(135deg, #e0e7ff, #f3f4f6); margin: 0; padding: 0; min-height: 100vh; }
408
+ .sidebar { position: fixed; left: 0; top: 0; width: 250px; height: 100%; background: rgba(255, 255, 255, 0.9); backdrop-filter: blur(10px); padding: 20px; box-shadow: 2px 0 15px rgba(0,0,0,0.1); transition: transform 0.3s ease; z-index: 1000; }
409
+ .sidebar-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; }
410
+ .nav-brand { font-size: 1.5em; font-weight: 600; color: #3b82f6; }
411
+ .nav-links { display: flex; flex-direction: column; gap: 10px; }
412
+ .nav-link { display: flex; align-items: center; gap: 10px; padding: 12px 15px; background: rgba(59, 130, 246, 0.1); color: #3b82f6; text-decoration: none; border-radius: 8px; transition: all 0.3s ease; }
413
+ .nav-link:hover { background: rgba(59, 130, 246, 0.3); color: #2563eb; transform: translateX(5px); }
414
+ .logout-btn { background: rgba(239, 68, 68, 0.1); color: #ef4444; }
415
+ .logout-btn:hover { background: rgba(239, 68, 68, 0.3); color: #dc2626; }
416
+ .menu-btn { display: none; font-size: 28px; background: rgba(255, 255, 255, 0.9); border: none; color: #3b82f6; cursor: pointer; position: fixed; top: 15px; left: 15px; z-index: 1001; padding: 5px 10px; border-radius: 5px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
417
+ .container { max-width: 800px; margin: 20px auto 20px 270px; background: rgba(255, 255, 255, 0.95); backdrop-filter: blur(5px); padding: 20px; border-radius: 12px; box-shadow: 0 4px 20px rgba(0,0,0,0.1); transition: margin-left 0.3s ease; }
418
  video, img { width: 100%; border-radius: 8px; max-height: 400px; object-fit: cover; }
419
+ .btn { display: inline-block; margin: 10px 0; padding: 12px 20px; background: rgba(59, 130, 246, 0.9); color: white; text-decoration: none; border-radius: 8px; border: none; cursor: pointer; transition: all 0.3s ease; }
420
+ .btn:hover { background: rgba(59, 130, 246, 1); transform: scale(1.05); }
421
+ .like-btn.liked { background: rgba(239, 68, 68, 0.9); }
422
+ .like-btn.liked:hover { background: rgba(239, 68, 68, 1); }
423
+ textarea { width: 100%; padding: 12px; margin: 10px 0; border: 1px solid #e2e8f0; border-radius: 8px; resize: vertical; background: rgba(255, 255, 255, 0.8); }
 
424
  .comment { border-top: 1px solid #e2e8f0; padding: 10px 0; }
425
  @media (max-width: 768px) {
426
+ .sidebar { transform: translateX(-100%); width: 200px; }
427
+ .sidebar.active { transform: translateX(0); }
 
428
  .menu-btn { display: block; }
429
+ .container { margin: 60px 10px 20px 10px; max-width: calc(100% - 20px); }
430
  video, img { max-height: 250px; }
431
+ .btn, textarea { width: 100%; font-size: 14px; padding: 10px; margin: 5px 0; }
432
+ h1 { font-size: 1.5em; }
433
+ h3 { font-size: 1.2em; }
434
  }
435
  </style>
436
  </head>
437
  <body>
438
  <button class="menu-btn" onclick="toggleSidebar()">☰</button>
439
+ ''' + NAV_HTML + '''
 
 
 
 
 
 
 
 
 
 
440
  <div class="container">
441
  <h1>{{ post['title'] }}</h1>
442
  {% if post['type'] == 'video' %}
 
450
  <p>Загрузил: {{ post['uploader'] }} | {{ post['upload_date'] }}</p>
451
  <p>Просмотров: {{ post['views'] }} | Лайков: {{ post['likes']|length }}</p>
452
  {% if is_authenticated %}
453
+ <form method="POST" style="display: inline;">
454
+ <button type="submit" name="like" class="btn like-btn {% if username in post['likes'] %}liked{% endif %}">
455
  {% if username in post['likes'] %}Убрать лайк{% else %}Лайк{% endif %}
456
  </button>
457
  </form>
458
  <form method="POST">
459
  <textarea name="comment" placeholder="Оставьте комментарий" rows="3"></textarea>
460
+ <button type="submit" class="btn">Отправить</button>
461
  </form>
462
  {% endif %}
463
  <h3>Комментарии</h3>
 
466
  <p><strong>{{ comment['user'] }}</strong> ({{ comment['date'] }}): {{ comment['text'] }}</p>
467
  </div>
468
  {% endfor %}
469
+ <a href="{{ url_for('feed') }}" class="btn">Назад к ленте</a>
470
  {% if not is_authenticated %}
471
  <p><a href="{{ url_for('login') }}">Войдите</a>, чтобы ставить лайки и комментировать.</p>
472
  {% endif %}
 
491
  data = load_data()
492
  username = session['username']
493
  user_posts = [p for p in data['posts'] if p['uploader'] == username]
494
+ is_authenticated = 'username' in session
495
 
496
  if request.method == 'POST':
497
  post_id = request.form.get('post_id')
 
510
  <title>Профиль - {{ username }}</title>
511
  <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet">
512
  <style>
513
+ body { font-family: 'Poppins', sans-serif; background: linear-gradient(135deg, #e0e7ff, #f3f4f6); margin: 0; padding: 0; min-height: 100vh; }
514
+ .sidebar { position: fixed; left: 0; top: 0; width: 250px; height: 100%; background: rgba(255, 255, 255, 0.9); backdrop-filter: blur(10px); padding: 20px; box-shadow: 2px 0 15px rgba(0,0,0,0.1); transition: transform 0.3s ease; z-index: 1000; }
515
+ .sidebar-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; }
516
+ .nav-brand { font-size: 1.5em; font-weight: 600; color: #3b82f6; }
517
+ .nav-links { display: flex; flex-direction: column; gap: 10px; }
518
+ .nav-link { display: flex; align-items: center; gap: 10px; padding: 12px 15px; background: rgba(59, 130, 246, 0.1); color: #3b82f6; text-decoration: none; border-radius: 8px; transition: all 0.3s ease; }
519
+ .nav-link:hover { background: rgba(59, 130, 246, 0.3); color: #2563eb; transform: translateX(5px); }
520
+ .logout-btn { background: rgba(239, 68, 68, 0.1); color: #ef4444; }
521
+ .logout-btn:hover { background: rgba(239, 68, 68, 0.3); color: #dc2626; }
522
+ .menu-btn { display: none; font-size: 28px; background: rgba(255, 255, 255, 0.9); border: none; color: #3b82f6; cursor: pointer; position: fixed; top: 15px; left: 15px; z-index: 1001; padding: 5px 10px; border-radius: 5px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
523
+ .container { max-width: 800px; margin: 20px auto 20px 270px; padding: 20px; transition: margin-left 0.3s ease; }
524
  .post-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 20px; }
525
+ .post-item { background: rgba(255, 255, 255, 0.95); backdrop-filter: blur(5px); padding: 15px; border-radius: 12px; box-shadow: 0 4px 20px rgba(0,0,0,0.1); transition: transform 0.3s ease; }
526
+ .post-item:hover { transform: scale(1.02); }
527
  .post-preview { width: 100%; border-radius: 8px; height: 200px; object-fit: cover; }
528
+ .btn { display: block; margin: 10px 0; padding: 12px 20px; background: rgba(59, 130, 246, 0.9); color: white; text-decoration: none; border-radius: 8px; border: none; cursor: pointer; transition: all 0.3s ease; }
529
+ .btn:hover { background: rgba(59, 130, 246, 1); transform: scale(1.05); }
530
+ .delete-btn { background: rgba(239, 68, 68, 0.9); }
531
+ .delete-btn:hover { background: rgba(239, 68, 68, 1); }
532
+ .stats { font-size: 0.9em; color: #666; margin-top: 5px; }
 
533
  @media (max-width: 768px) {
534
+ .sidebar { transform: translateX(-100%); width: 200px; }
535
+ .sidebar.active { transform: translateX(0); }
 
536
  .menu-btn { display: block; }
537
+ .container { margin: 60px 10px 20px 10px; max-width: calc(100% - 20px); }
538
  .post-grid { grid-template-columns: 1fr; gap: 15px; }
539
  .post-item { padding: 10px; }
540
  .post-preview { height: 150px; }
541
+ .btn { font-size: 14px; padding: 10px; }
542
+ h1, h2 { font-size: 1.5em; }
543
  }
544
  </style>
545
  </head>
546
  <body>
547
  <button class="menu-btn" onclick="toggleSidebar()">☰</button>
548
+ ''' + NAV_HTML + '''
 
 
 
 
 
549
  <div class="container">
550
  <h1>Профиль: {{ username }}</h1>
551
+ <a href="{{ url_for('upload') }}" class="btn">Добавить публикацию</a>
552
  <h2>Ваши публикации</h2>
553
  <div class="post-grid">
554
  {% if user_posts %}
 
569
  <p class="stats">Просмотров: {{ post['views'] }} | Лайков: {{ post['likes']|length }}</p>
570
  <form method="POST">
571
  <input type="hidden" name="post_id" value="{{ post['id'] }}">
572
+ <button type="submit" class="btn delete-btn">Удалить</button>
573
  </form>
574
  </div>
575
  {% endfor %}
 
598
  </body>
599
  </html>
600
  '''
601
+ return render_template_string(html, username=username, user_posts=user_posts, repo_id=REPO_ID, is_authenticated=is_authenticated)
602
 
603
  # Страница загрузки контента
604
  @app.route('/upload', methods=['GET', 'POST'])
 
660
 
661
  return redirect(url_for('profile'))
662
 
663
+ is_authenticated = 'username' in session
664
+ username = session.get('username', None)
665
  html = '''
666
  <!DOCTYPE html>
667
  <html lang="ru">
 
671
  <title>Загрузка контента</title>
672
  <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet">
673
  <style>
674
+ body { font-family: 'Poppins', sans-serif; background: linear-gradient(135deg, #e0e7ff, #f3f4f6); margin: 0; padding: 0; min-height: 100vh; }
675
+ .sidebar { position: fixed; left: 0; top: 0; width: 250px; height: 100%; background: rgba(255, 255, 255, 0.9); backdrop-filter: blur(10px); padding: 20px; box-shadow: 2px 0 15px rgba(0,0,0,0.1); transition: transform 0.3s ease; z-index: 1000; }
676
+ .sidebar-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; }
677
+ .nav-brand { font-size: 1.5em; font-weight: 600; color: #3b82f6; }
678
+ .nav-links { display: flex; flex-direction: column; gap: 10px; }
679
+ .nav-link { display: flex; align-items: center; gap: 10px; padding: 12px 15px; background: rgba(59, 130, 246, 0.1); color: #3b82f6; text-decoration: none; border-radius: 8px; transition: all 0.3s ease; }
680
+ .nav-link:hover { background: rgba(59, 130, 246, 0.3); color: #2563eb; transform: translateX(5px); }
681
+ .logout-btn { background: rgba(239, 68, 68, 0.1); color: #ef4444; }
682
+ .logout-btn:hover { background: rgba(239, 68, 68, 0.3); color: #dc2626; }
683
+ .menu-btn { display: none; font-size: 28px; background: rgba(255, 255, 255, 0.9); border: none; color: #3b82f6; cursor: pointer; position: fixed; top: 15px; left: 15px; z-index: 1001; padding: 5px 10px; border-radius: 5px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
684
+ .container { max-width: 600px; margin: 20px auto 20px 270px; background: rgba(255, 255, 255, 0.95); backdrop-filter: blur(5px); padding: 20px; border-radius: 12px; box-shadow: 0 4px 20px rgba(0,0,0,0.1); transition: margin-left 0.3s ease; }
685
+ input, textarea { width: 100%; padding: 12px; margin: 10px 0; border: 1px solid #e2e8f0; border-radius: 8px; box-sizing: border-box; background: rgba(255, 255, 255, 0.8); }
686
+ button { padding: 12px; background: #3b82f6; color: white; border: none; border-radius: 8px; cursor: pointer; width: 100%; transition: background 0.3s ease; }
687
+ button:hover { background: #2563eb; }
688
  #progress-container { margin-top: 10px; }
689
+ #progress-bar { width: 0%; height: 20px; background: #3b82f6; border-radius: 8px; transition: width 0.3s ease; }
 
 
 
 
690
  @media (max-width: 768px) {
691
+ .sidebar { transform: translateX(-100%); width: 200px; }
692
+ .sidebar.active { transform: translateX(0); }
 
693
  .menu-btn { display: block; }
694
+ .container { margin: 60px 10px 20px 10px; max-width: calc(100% - 20px); }
695
+ input, textarea, button { font-size: 14px; padding: 10px; margin: 5px 0; }
696
+ h1 { font-size: 1.5em; }
697
  #progress-container { height: 15px; }
698
  #progress-bar { height: 15px; }
699
  }
 
701
  </head>
702
  <body>
703
  <button class="menu-btn" onclick="toggleSidebar()">☰</button>
704
+ ''' + NAV_HTML + '''
 
 
 
 
 
705
  <div class="container">
706
  <h1>Загрузить контент</h1>
707
  <form id="upload-form" enctype="multipart/form-data">
 
751
  </body>
752
  </html>
753
  '''
754
+ return render_template_string(html, username=username, is_authenticated=is_authenticated)
755
 
756
  if __name__ == '__main__':
757
  backup_thread = threading.Thread(target=periodic_backup, daemon=True)