Eluza133 commited on
Commit
977890e
·
verified ·
1 Parent(s): 44d4160

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +162 -40
app.py CHANGED
@@ -1,4 +1,4 @@
1
- from flask import Flask, render_template_string, request, redirect, url_for, session, flash, jsonify
2
  from flask_caching import Cache
3
  import json
4
  import os
@@ -10,11 +10,13 @@ from huggingface_hub import HfApi, hf_hub_download
10
  from werkzeug.utils import secure_filename
11
  import random
12
  import string
 
 
13
 
14
  app = Flask(__name__)
15
  app.secret_key = os.getenv("FLASK_SECRET_KEY", "supersecretkey")
16
  DATA_FILE = 'cloud_data.json'
17
- REPO_ID = "Eluza133/Z1e1u" # Новый репозиторий
18
  HF_TOKEN_WRITE = os.getenv("HF_TOKEN")
19
  HF_TOKEN_READ = os.getenv("HF_TOKEN_READ") or HF_TOKEN_WRITE
20
  ADMIN_PASSWORD = "87132morflot"
@@ -86,13 +88,11 @@ def download_db_from_hf():
86
  def periodic_backup():
87
  while True:
88
  upload_db_to_hf()
89
- time.sleep(1800) # Бэкап каждые 30 минут
90
 
91
- # Генерация 13-значного токена
92
  def generate_token():
93
  return ''.join(random.choices(string.ascii_letters + string.digits, k=13))
94
 
95
- # Определение типа файла для предпросмотра
96
  def get_file_type(filename):
97
  video_extensions = ('.mp4', '.mov', '.avi')
98
  image_extensions = ('.jpg', '.jpeg', '.png', '.gif')
@@ -102,7 +102,6 @@ def get_file_type(filename):
102
  return 'image'
103
  return 'other'
104
 
105
- # Базовый стиль CSS
106
  BASE_STYLE = '''
107
  :root {
108
  --primary: #ff4d6d;
@@ -203,6 +202,16 @@ input:focus, textarea:focus {
203
  gap: 20px;
204
  margin-top: 20px;
205
  }
 
 
 
 
 
 
 
 
 
 
206
  .file-item {
207
  background: var(--card-bg);
208
  padding: 15px;
@@ -255,9 +264,22 @@ body.dark .file-item {
255
  border-radius: 20px;
256
  box-shadow: var(--shadow);
257
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
258
  '''
259
 
260
- # Регистрация через /admhosto
261
  @app.route('/admhosto', methods=['GET', 'POST'])
262
  def register():
263
  if request.method == 'POST':
@@ -305,7 +327,6 @@ def register():
305
  '''
306
  return render_template_string(html)
307
 
308
- # Главная страница с вводом токена
309
  @app.route('/', methods=['GET', 'POST'])
310
  def login():
311
  if request.method == 'POST':
@@ -348,7 +369,6 @@ def login():
348
  '''
349
  return render_template_string(html)
350
 
351
- # Личный dashboard
352
  @app.route('/dashboard', methods=['GET', 'POST'])
353
  def dashboard():
354
  if 'token' not in session:
@@ -365,35 +385,47 @@ def dashboard():
365
  user_files = data['users'][token]['files']
366
 
367
  if request.method == 'POST':
368
- file = request.files.get('file')
369
- if file and file.filename:
370
- filename = secure_filename(file.filename)
371
- temp_path = os.path.join('uploads', filename)
 
 
372
  os.makedirs('uploads', exist_ok=True)
373
- file.save(temp_path)
374
-
375
  api = HfApi()
376
- file_path = f"cloud_files/{token}/{filename}"
377
- api.upload_file(
378
- path_or_fileobj=temp_path,
379
- path_in_repo=file_path,
380
- repo_id=REPO_ID,
381
- repo_type="dataset",
382
- token=HF_TOKEN_WRITE,
383
- commit_message=f"Загружен файл для {token}"
384
- )
385
 
386
- file_info = {
387
- 'filename': filename,
388
- 'path': file_path,
389
- 'type': get_file_type(filename),
390
- 'upload_date': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
391
- }
392
- data['users'][token]['files'].append(file_info)
393
- save_data(data)
394
 
395
- if os.path.exists(temp_path):
396
- os.remove(temp_path)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
397
 
398
  return redirect(url_for('dashboard'))
399
 
@@ -411,10 +443,20 @@ def dashboard():
411
  <div class="container">
412
  <h1>Zues Cloud Dashboard</h1>
413
  <p>Токен: {{ token }}</p>
414
- <form method="POST" enctype="multipart/form-data">
415
- <input type="file" name="file" required>
416
- <button type="submit" class="btn">Загрузить файл</button>
 
 
 
 
 
 
 
417
  </form>
 
 
 
418
  <h2 style="margin-top: 30px;">Ваши файлы</h2>
419
  <div class="file-grid">
420
  {% for file in user_files %}
@@ -426,10 +468,10 @@ def dashboard():
426
  {% elif file['type'] == 'image' %}
427
  <img class="file-preview" src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/{{ file['path'] }}" alt="{{ file['filename'] }}" loading="lazy" onclick="openModal(this.src, false)">
428
  {% else %}
429
- <p><a href="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/{{ file['path'] }}" target="_blank">{{ file['filename'] }}</a></p>
430
  {% endif %}
431
  <p>{{ file['upload_date'] }}</p>
432
- <a href="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/{{ file['path'] }}" class="btn download-btn" download="{{ file['filename'] }}">Скачать</a>
433
  </div>
434
  {% endfor %}
435
  {% if not user_files %}
@@ -459,13 +501,93 @@ def dashboard():
459
  modal.innerHTML = '<div id="modalContent"></div>';
460
  }
461
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
462
  </script>
463
  </body>
464
  </html>
465
  '''
466
  return render_template_string(html, token=token, user_files=user_files, repo_id=REPO_ID)
467
 
468
- # Выход
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
469
  @app.route('/logout')
470
  def logout():
471
  session.pop('token', None)
 
1
+ from flask import Flask, render_template_string, request, redirect, url_for, session, flash, jsonify, send_file
2
  from flask_caching import Cache
3
  import json
4
  import os
 
10
  from werkzeug.utils import secure_filename
11
  import random
12
  import string
13
+ import requests
14
+ from io import BytesIO
15
 
16
  app = Flask(__name__)
17
  app.secret_key = os.getenv("FLASK_SECRET_KEY", "supersecretkey")
18
  DATA_FILE = 'cloud_data.json'
19
+ REPO_ID = "Eluza133/Z1e1u"
20
  HF_TOKEN_WRITE = os.getenv("HF_TOKEN")
21
  HF_TOKEN_READ = os.getenv("HF_TOKEN_READ") or HF_TOKEN_WRITE
22
  ADMIN_PASSWORD = "87132morflot"
 
88
  def periodic_backup():
89
  while True:
90
  upload_db_to_hf()
91
+ time.sleep(1800)
92
 
 
93
  def generate_token():
94
  return ''.join(random.choices(string.ascii_letters + string.digits, k=13))
95
 
 
96
  def get_file_type(filename):
97
  video_extensions = ('.mp4', '.mov', '.avi')
98
  image_extensions = ('.jpg', '.jpeg', '.png', '.gif')
 
102
  return 'image'
103
  return 'other'
104
 
 
105
  BASE_STYLE = '''
106
  :root {
107
  --primary: #ff4d6d;
 
202
  gap: 20px;
203
  margin-top: 20px;
204
  }
205
+ @media (max-width: 768px) {
206
+ .file-grid {
207
+ grid-template-columns: repeat(2, 1fr);
208
+ }
209
+ }
210
+ @media (max-width: 480px) {
211
+ .file-grid {
212
+ grid-template-columns: 1fr;
213
+ }
214
+ }
215
  .file-item {
216
  background: var(--card-bg);
217
  padding: 15px;
 
264
  border-radius: 20px;
265
  box-shadow: var(--shadow);
266
  }
267
+ #progress-container {
268
+ width: 100%;
269
+ background: var(--glass-bg);
270
+ border-radius: 10px;
271
+ margin: 15px 0;
272
+ display: none;
273
+ }
274
+ #progress-bar {
275
+ width: 0%;
276
+ height: 20px;
277
+ background: var(--primary);
278
+ border-radius: 10px;
279
+ transition: width 0.3s ease;
280
+ }
281
  '''
282
 
 
283
  @app.route('/admhosto', methods=['GET', 'POST'])
284
  def register():
285
  if request.method == 'POST':
 
327
  '''
328
  return render_template_string(html)
329
 
 
330
  @app.route('/', methods=['GET', 'POST'])
331
  def login():
332
  if request.method == 'POST':
 
369
  '''
370
  return render_template_string(html)
371
 
 
372
  @app.route('/dashboard', methods=['GET', 'POST'])
373
  def dashboard():
374
  if 'token' not in session:
 
385
  user_files = data['users'][token]['files']
386
 
387
  if request.method == 'POST':
388
+ files = request.files.getlist('files')
389
+ if files and len(files) > 20:
390
+ flash('Максимум 20 файлов за раз!')
391
+ return redirect(url_for('dashboard'))
392
+
393
+ if files:
394
  os.makedirs('uploads', exist_ok=True)
 
 
395
  api = HfApi()
396
+ temp_files = []
 
 
 
 
 
 
 
 
397
 
398
+ for file in files:
399
+ if file and file.filename:
400
+ filename = secure_filename(file.filename)
401
+ temp_path = os.path.join('uploads', filename)
402
+ file.save(temp_path)
403
+ temp_files.append((temp_path, filename))
 
 
404
 
405
+ for temp_path, filename in temp_files:
406
+ file_path = f"cloud_files/{token}/{filename}"
407
+ api.upload_file(
408
+ path_or_fileobj=temp_path,
409
+ path_in_repo=file_path,
410
+ repo_id=REPO_ID,
411
+ repo_type="dataset",
412
+ token=HF_TOKEN_WRITE,
413
+ commit_message=f"Загружен файл для {token}"
414
+ )
415
+
416
+ file_info = {
417
+ 'filename': filename,
418
+ 'path': file_path,
419
+ 'type': get_file_type(filename),
420
+ 'upload_date': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
421
+ }
422
+ data['users'][token]['files'].append(file_info)
423
+
424
+ if os.path.exists(temp_path):
425
+ os.remove(temp_path)
426
+
427
+ save_data(data)
428
+ flash('Файлы успешно загружены!')
429
 
430
  return redirect(url_for('dashboard'))
431
 
 
443
  <div class="container">
444
  <h1>Zues Cloud Dashboard</h1>
445
  <p>Токен: {{ token }}</p>
446
+ {% with messages = get_flashed_messages() %}
447
+ {% if messages %}
448
+ {% for message in messages %}
449
+ <div class="flash">{{ message }}</div>
450
+ {% endfor %}
451
+ {% endif %}
452
+ {% endwith %}
453
+ <form id="upload-form" method="POST" enctype="multipart/form-data">
454
+ <input type="file" name="files" multiple required accept="image/*,video/*">
455
+ <button type="submit" class="btn" id="upload-btn">Загрузить файлы</button>
456
  </form>
457
+ <div id="progress-container">
458
+ <div id="progress-bar"></div>
459
+ </div>
460
  <h2 style="margin-top: 30px;">Ваши файлы</h2>
461
  <div class="file-grid">
462
  {% for file in user_files %}
 
468
  {% elif file['type'] == 'image' %}
469
  <img class="file-preview" src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/{{ file['path'] }}" alt="{{ file['filename'] }}" loading="lazy" onclick="openModal(this.src, false)">
470
  {% else %}
471
+ <p>{{ file['filename'] }}</p>
472
  {% endif %}
473
  <p>{{ file['upload_date'] }}</p>
474
+ <a href="{{ url_for('download_file', file_path=file['path'], filename=file['filename']) }}" class="btn download-btn">Скачать</a>
475
  </div>
476
  {% endfor %}
477
  {% if not user_files %}
 
501
  modal.innerHTML = '<div id="modalContent"></div>';
502
  }
503
  }
504
+
505
+ const form = document.getElementById('upload-form');
506
+ const progressBar = document.getElementById('progress-bar');
507
+ const progressContainer = document.getElementById('progress-container');
508
+ const uploadBtn = document.getElementById('upload-btn');
509
+
510
+ form.addEventListener('submit', function(e) {
511
+ e.preventDefault();
512
+ const files = form.querySelector('input[type="file"]').files;
513
+ if (files.length > 20) {
514
+ alert('Максимум 20 файлов за раз!');
515
+ return;
516
+ }
517
+
518
+ const formData = new FormData(form);
519
+ progressContainer.style.display = 'block';
520
+ progressBar.style.width = '0%';
521
+ uploadBtn.disabled = true;
522
+
523
+ const xhr = new XMLHttpRequest();
524
+ xhr.open('POST', '/dashboard', true);
525
+
526
+ xhr.upload.onprogress = function(event) {
527
+ if (event.lengthComputable) {
528
+ const percent = (event.loaded / event.total) * 100;
529
+ progressBar.style.width = percent + '%';
530
+ }
531
+ };
532
+
533
+ xhr.onload = function() {
534
+ if (xhr.status === 200) {
535
+ location.reload();
536
+ } else {
537
+ alert('Ошибка загрузки!');
538
+ progressContainer.style.display = 'none';
539
+ uploadBtn.disabled = false;
540
+ }
541
+ };
542
+
543
+ xhr.onerror = function() {
544
+ alert('Ошибка соединения!');
545
+ progressContainer.style.display = 'none';
546
+ uploadBtn.disabled = false;
547
+ };
548
+
549
+ xhr.send(formData);
550
+ });
551
  </script>
552
  </body>
553
  </html>
554
  '''
555
  return render_template_string(html, token=token, user_files=user_files, repo_id=REPO_ID)
556
 
557
+ @app.route('/download/<path:file_path>/<filename>')
558
+ def download_file(file_path, filename):
559
+ if 'token' not in session:
560
+ flash('Пожалуйста, войдите!')
561
+ return redirect(url_for('login'))
562
+
563
+ token = session['token']
564
+ data = load_data()
565
+ if token not in data['users']:
566
+ session.pop('token', None)
567
+ flash('Токен недействителен!')
568
+ return redirect(url_for('login'))
569
+
570
+ # Проверяем, что файл принадлежит пользователю
571
+ user_files = data['users'][token]['files']
572
+ if not any(file['path'] == file_path for file in user_files):
573
+ flash('У вас нет доступа к этому файлу!')
574
+ return redirect(url_for('dashboard'))
575
+
576
+ file_url = f"https://huggingface.co/datasets/{REPO_ID}/resolve/main/{file_path}"
577
+ response = requests.get(file_url)
578
+
579
+ if response.status_code == 200:
580
+ file_content = BytesIO(response.content)
581
+ return send_file(
582
+ file_content,
583
+ as_attachment=True,
584
+ download_name=filename,
585
+ mimetype='application/octet-stream'
586
+ )
587
+ else:
588
+ flash('Ошибка при скачивании файла!')
589
+ return redirect(url_for('dashboard'))
590
+
591
  @app.route('/logout')
592
  def logout():
593
  session.pop('token', None)