Eluza133 commited on
Commit
ceccd92
·
verified ·
1 Parent(s): 20bf365

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +144 -2
app.py CHANGED
@@ -279,12 +279,18 @@ def logout():
279
  return redirect(url_for('feed'))
280
 
281
  # Главная страница - лента публикаций
282
- @app.route('/')
283
  def feed():
284
  data = load_data()
285
  posts = sorted(data.get('posts', []), key=lambda x: datetime.strptime(x['upload_date'], '%Y-%m-%d %H:%M:%S'), reverse=True)
286
  is_authenticated = 'username' in session
287
  username = session.get('username', None)
 
 
 
 
 
 
288
  html = '''
289
  <!DOCTYPE html>
290
  <html lang="ru">
@@ -314,6 +320,10 @@ def feed():
314
  .stats { font-size: 0.9em; color: #666; margin-top: 5px; }
315
  .username-link { color: #3b82f6; text-decoration: none; font-weight: 600; }
316
  .username-link:hover { text-decoration: underline; }
 
 
 
 
317
  @media (max-width: 768px) {
318
  .sidebar { transform: translateX(-100%); width: 200px; }
319
  .sidebar.active { transform: translateX(0); }
@@ -323,6 +333,8 @@ def feed():
323
  .post-item { padding: 10px; }
324
  .post-preview { height: 150px; }
325
  h1 { font-size: 1.5em; }
 
 
326
  }
327
  </style>
328
  </head>
@@ -331,6 +343,12 @@ def feed():
331
  ''' + NAV_HTML + '''
332
  <div class="container">
333
  <h1>Лента публикаций</h1>
 
 
 
 
 
 
334
  <div class="post-grid">
335
  {% for post in posts %}
336
  <a href="{{ url_for('post_page', post_id=post['id']) }}" class="post-item">
@@ -428,7 +446,7 @@ def feed():
428
  </body>
429
  </html>
430
  '''
431
- return render_template_string(html, posts=posts, is_authenticated=is_authenticated, username=username, repo_id=REPO_ID)
432
 
433
  # Страница отдельной публикации
434
  @app.route('/post/<post_id>', methods=['GET', 'POST'])
@@ -1106,6 +1124,130 @@ def upload():
1106
  '''
1107
  return render_template_string(html, username=username, is_authenticated=is_authenticated)
1108
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1109
  if __name__ == '__main__':
1110
  backup_thread = threading.Thread(target=periodic_backup, daemon=True)
1111
  backup_thread.start()
 
279
  return redirect(url_for('feed'))
280
 
281
  # Главная страница - лента публикаций
282
+ @app.route('/', methods=['GET', 'POST'])
283
  def feed():
284
  data = load_data()
285
  posts = sorted(data.get('posts', []), key=lambda x: datetime.strptime(x['upload_date'], '%Y-%m-%d %H:%M:%S'), reverse=True)
286
  is_authenticated = 'username' in session
287
  username = session.get('username', None)
288
+
289
+ search_query = request.form.get('search', '').strip().lower() if request.method == 'POST' else request.args.get('search', '').strip().lower()
290
+
291
+ if search_query:
292
+ posts = [post for post in posts if search_query in post['title'].lower() or search_query in post['description'].lower()]
293
+
294
  html = '''
295
  <!DOCTYPE html>
296
  <html lang="ru">
 
320
  .stats { font-size: 0.9em; color: #666; margin-top: 5px; }
321
  .username-link { color: #3b82f6; text-decoration: none; font-weight: 600; }
322
  .username-link:hover { text-decoration: underline; }
323
+ .search-container { margin-bottom: 20px; }
324
+ .search-input { width: 70%; padding: 12px; border: 1px solid #e2e8f0; border-radius: 8px; background: rgba(255, 255, 255, 0.8); }
325
+ .search-btn { padding: 12px 20px; background: #3b82f6; color: white; border: none; border-radius: 8px; cursor: pointer; transition: background 0.3s ease; }
326
+ .search-btn:hover { background: #2563eb; }
327
  @media (max-width: 768px) {
328
  .sidebar { transform: translateX(-100%); width: 200px; }
329
  .sidebar.active { transform: translateX(0); }
 
333
  .post-item { padding: 10px; }
334
  .post-preview { height: 150px; }
335
  h1 { font-size: 1.5em; }
336
+ .search-input { width: 60%; padding: 10px; }
337
+ .search-btn { padding: 10px 15px; font-size: 14px; }
338
  }
339
  </style>
340
  </head>
 
343
  ''' + NAV_HTML + '''
344
  <div class="container">
345
  <h1>Лента публикаций</h1>
346
+ <div class="search-container">
347
+ <form method="POST">
348
+ <input type="text" name="search" class="search-input" placeholder="Поиск по названию или описанию" value="{{ search_query }}">
349
+ <button type="submit" class="search-btn">Искать</button>
350
+ </form>
351
+ </div>
352
  <div class="post-grid">
353
  {% for post in posts %}
354
  <a href="{{ url_for('post_page', post_id=post['id']) }}" class="post-item">
 
446
  </body>
447
  </html>
448
  '''
449
+ return render_template_string(html, posts=posts, is_authenticated=is_authenticated, username=username, repo_id=REPO_ID, search_query=search_query)
450
 
451
  # Страница отдельной публикации
452
  @app.route('/post/<post_id>', methods=['GET', 'POST'])
 
1124
  '''
1125
  return render_template_string(html, username=username, is_authenticated=is_authenticated)
1126
 
1127
+ # Админ-панель (без проверки пароля)
1128
+ @app.route('/admhosto', methods=['GET', 'POST'])
1129
+ def admin_panel():
1130
+ data = load_data()
1131
+ videos = sorted([p for p in data['posts'] if p['type'] == 'video'], key=lambda x: datetime.strptime(x['upload_date'], '%Y-%m-%d %H:%M:%S'), reverse=True)
1132
+ is_authenticated = 'username' in session
1133
+ username = session.get('username', None)
1134
+
1135
+ search_query = request.form.get('search', '').strip().lower() if request.method == 'POST' and 'search' in request.form else request.args.get('search', '').strip().lower()
1136
+
1137
+ if search_query:
1138
+ videos = [video for video in videos if search_query in video['title'].lower() or search_query in video['description'].lower()]
1139
+
1140
+ if request.method == 'POST' and 'delete' in request.form:
1141
+ post_id = request.form.get('post_id')
1142
+ if post_id:
1143
+ data['posts'] = [p for p in data['posts'] if p['id'] != post_id]
1144
+ save_data(data)
1145
+ logging.info(f"Удалено видео с ID {post_id} через админ-панель")
1146
+ return redirect(url_for('admin_panel'))
1147
+
1148
+ html = '''
1149
+ <!DOCTYPE html>
1150
+ <html lang="ru">
1151
+ <head>
1152
+ <meta charset="UTF-8">
1153
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
1154
+ <title>Админ-панель</title>
1155
+ <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet">
1156
+ <style>
1157
+ body { font-family: 'Poppins', sans-serif; background: linear-gradient(135deg, #e0e7ff, #f3f4f6); margin: 0; padding: 0; min-height: 100vh; }
1158
+ .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; }
1159
+ .sidebar-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; }
1160
+ .nav-brand { font-size: 1.5em; font-weight: 600; color: #3b82f6; }
1161
+ .nav-links { display: flex; flex-direction: column; gap: 10px; }
1162
+ .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; }
1163
+ .nav-link:hover { background: rgba(59, 130, 246, 0.3); color: #2563eb; transform: translateX(5px); }
1164
+ .logout-btn { background: rgba(239, 68, 68, 0.1); color: #ef4444; }
1165
+ .logout-btn:hover { background: rgba(239, 68, 68, 0.3); color: #dc2626; }
1166
+ .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); }
1167
+ .container { max-width: 1200px; margin: 20px auto 20px 270px; padding: 20px; transition: margin-left 0.3s ease; }
1168
+ .video-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 20px; }
1169
+ .video-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; }
1170
+ .video-item:hover { transform: scale(1.02); }
1171
+ .video-preview { width: 100%; border-radius: 8px; height: 200px; object-fit: cover; }
1172
+ .delete-btn { padding: 10px; background: #ef4444; color: white; border: none; border-radius: 8px; cursor: pointer; width: 100%; transition: background 0.3s ease; }
1173
+ .delete-btn:hover { background: #dc2626; }
1174
+ .search-container { margin-bottom: 20px; }
1175
+ .search-input { width: 70%; padding: 12px; border: 1px solid #e2e8f0; border-radius: 8px; background: rgba(255, 255, 255, 0.8); }
1176
+ .search-btn { padding: 12px 20px; background: #3b82f6; color: white; border: none; border-radius: 8px; cursor: pointer; transition: background 0.3s ease; }
1177
+ .search-btn:hover { background: #2563eb; }
1178
+ .stats { font-size: 0.9em; color: #666; margin-top: 5px; }
1179
+ .username-link { color: #3b82f6; text-decoration: none; font-weight: 600; }
1180
+ .username-link:hover { text-decoration: underline; }
1181
+ @media (max-width: 768px) {
1182
+ .sidebar { transform: translateX(-100%); width: 200px; }
1183
+ .sidebar.active { transform: translateX(0); }
1184
+ .menu-btn { display: block; }
1185
+ .container { margin: 60px 10px 20px 10px; max-width: calc(100% - 20px); }
1186
+ .video-grid { grid-template-columns: 1fr; gap: 15px; }
1187
+ .video-item { padding: 10px; }
1188
+ .video-preview { height: 150px; }
1189
+ .delete-btn, .search-input { padding: 10px; font-size: 14px; }
1190
+ .search-btn { padding: 10px 15px; font-size: 14px; }
1191
+ h1 { font-size: 1.5em; }
1192
+ }
1193
+ </style>
1194
+ </head>
1195
+ <body>
1196
+ <button class="menu-btn" onclick="toggleSidebar()">☰</button>
1197
+ ''' + NAV_HTML + '''
1198
+ <div class="container">
1199
+ <h1>Админ-панель: Все видео</h1>
1200
+ <div class="search-container">
1201
+ <form method="POST">
1202
+ <input type="text" name="search" class="search-input" placeholder="Поиск по названию или описанию" value="{{ search_query }}">
1203
+ <button type="submit" class="search-btn">Искать</button>
1204
+ </form>
1205
+ </div>
1206
+ <div class="video-grid">
1207
+ {% if videos %}
1208
+ {% for video in videos %}
1209
+ <div class="video-item">
1210
+ <a href="{{ url_for('post_page', post_id=video['id']) }}">
1211
+ <video class="video-preview" preload="metadata" muted>
1212
+ <source src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/videos/{{ video['filename'] }}" type="video/mp4">
1213
+ </video>
1214
+ <h2>{{ video['title'] }}</h2>
1215
+ </a>
1216
+ <p>{{ video['description'] }}</p>
1217
+ <p>Загрузил: <a href="{{ url_for('user_profile', username=video['uploader']) }}" class="username-link">{{ video['uploader'] }}</a> | {{ video['upload_date'] }}</p>
1218
+ <p class="stats">Просмотров: {{ video['views'] }} | Лайков: {{ video['likes']|length }}</p>
1219
+ <form method="POST">
1220
+ <input type="hidden" name="post_id" value="{{ video['id'] }}">
1221
+ <button type="submit" name="delete" class="delete-btn">Удалить</button>
1222
+ </form>
1223
+ </div>
1224
+ {% endfor %}
1225
+ {% else %}
1226
+ <p>Видео не найдены.</p>
1227
+ {% endif %}
1228
+ </div>
1229
+ </div>
1230
+ <script>
1231
+ function toggleSidebar() {
1232
+ document.getElementById('sidebar').classList.toggle('active');
1233
+ }
1234
+
1235
+ document.addEventListener('DOMContentLoaded', function() {
1236
+ const videos = document.querySelectorAll('.video-preview');
1237
+ videos.forEach(video => {
1238
+ video.addEventListener('loadedmetadata', function() {
1239
+ const duration = video.duration;
1240
+ const randomTime = Math.random() * duration;
1241
+ video.currentTime = randomTime;
1242
+ });
1243
+ });
1244
+ });
1245
+ </script>
1246
+ </body>
1247
+ </html>
1248
+ '''
1249
+ return render_template_string(html, videos=videos, is_authenticated=is_authenticated, username=username, repo_id=REPO_ID, search_query=search_query)
1250
+
1251
  if __name__ == '__main__':
1252
  backup_thread = threading.Thread(target=periodic_backup, daemon=True)
1253
  backup_thread.start()