Eluza133 commited on
Commit
387e8f2
·
verified ·
1 Parent(s): a75f065

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +235 -0
app.py ADDED
@@ -0,0 +1,235 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, render_template_string, request, redirect, url_for, Response, jsonify
2
+ import json
3
+ import os
4
+ import logging
5
+ import threading
6
+ import time
7
+ from datetime import datetime
8
+ from huggingface_hub import HfApi, hf_hub_download
9
+ from werkzeug.utils import secure_filename
10
+
11
+ app = Flask(__name__)
12
+ DATA_FILE = 'datatest.json'
13
+ REPO_ID = "Eluza133/w1f9"
14
+ HF_TOKEN_WRITE = os.getenv("HF_TOKEN") # Убедитесь, что токен имеет права на запись
15
+ HF_TOKEN_READ = os.getenv("HF_TOKEN_READ") or HF_TOKEN_WRITE
16
+
17
+ # Настройка логирования
18
+ logging.basicConfig(level=logging.DEBUG)
19
+
20
+ # Функции работы с базой данных
21
+ def load_data():
22
+ try:
23
+ download_db_from_hf()
24
+ with open(DATA_FILE, 'r', encoding='utf-8') as file:
25
+ data = json.load(file)
26
+ if not isinstance(data, dict) or 'videos' not in data:
27
+ return {'videos': []}
28
+ return data
29
+ except Exception as e:
30
+ logging.error(f"Ошибка загрузки данных: {e}")
31
+ return {'videos': []}
32
+
33
+ def save_data(data):
34
+ try:
35
+ with open(DATA_FILE, 'w', encoding='utf-8') as file:
36
+ json.dump(data, file, ensure_ascii=False, indent=4)
37
+ upload_db_to_hf()
38
+ except Exception as e:
39
+ logging.error(f"Ошибка сохранения данных: {e}")
40
+ raise
41
+
42
+ def upload_db_to_hf():
43
+ try:
44
+ api = HfApi()
45
+ api.upload_file(
46
+ path_or_fileobj=DATA_FILE,
47
+ path_in_repo=DATA_FILE,
48
+ repo_id=REPO_ID,
49
+ repo_type="dataset",
50
+ token=HF_TOKEN_WRITE,
51
+ commit_message=f"Backup {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
52
+ )
53
+ logging.info("База данных загружена на Hugging Face")
54
+ except Exception as e:
55
+ logging.error(f"Ошибка загрузки базы: {e}")
56
+
57
+ def download_db_from_hf():
58
+ try:
59
+ hf_hub_download(
60
+ repo_id=REPO_ID,
61
+ filename=DATA_FILE,
62
+ repo_type="dataset",
63
+ token=HF_TOKEN_READ,
64
+ local_dir=".",
65
+ local_dir_use_symlinks=False
66
+ )
67
+ logging.info("База данных скачана с Hugging Face")
68
+ except Exception as e:
69
+ logging.error(f"Ошибка скачивания базы: {e}")
70
+ raise
71
+
72
+ def periodic_backup():
73
+ while True:
74
+ upload_db_to_hf()
75
+ time.sleep(15)
76
+
77
+ # Главная страница - лента видео
78
+ @app.route('/')
79
+ def video_feed():
80
+ data = load_data()
81
+ videos = data['videos']
82
+ html = '''
83
+ <!DOCTYPE html>
84
+ <html lang="ru">
85
+ <head>
86
+ <meta charset="UTF-8">
87
+ <title>Видеохостинг</title>
88
+ <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet">
89
+ <style>
90
+ body { font-family: 'Poppins', sans-serif; background: #f0f2f5; padding: 20px; }
91
+ .container { max-width: 1200px; margin: 0 auto; }
92
+ .video-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 20px; }
93
+ .video-item { background: #fff; padding: 15px; border-radius: 10px; box-shadow: 0 4px 15px rgba(0,0,0,0.1); }
94
+ .video-item video { width: 100%; border-radius: 8px; }
95
+ .upload-btn { display: block; margin: 20px auto; padding: 10px 20px; background: #3b82f6; color: white; text-align: center; text-decoration: none; border-radius: 8px; }
96
+ #progress-bar { display: none; width: 100%; height: 20px; margin-top: 10px; }
97
+ </style>
98
+ </head>
99
+ <body>
100
+ <div class="container">
101
+ <h1>Лента видео</h1>
102
+ <a href="/upload" class="upload-btn">Загрузить видео</a>
103
+ <div class="video-grid">
104
+ {% for video in videos %}
105
+ <div class="video-item">
106
+ <h2>{{ video['title'] }}</h2>
107
+ <p>{{ video['description'] }}</p>
108
+ <video controls>
109
+ <source src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/videos/{{ video['filename'] }}" type="video/mp4">
110
+ </video>
111
+ <p>Загрузил: {{ video['uploader'] }} | {{ video['upload_date'] }}</p>
112
+ </div>
113
+ {% endfor %}
114
+ </div>
115
+ </div>
116
+ </body>
117
+ </html>
118
+ '''
119
+ return render_template_string(html, videos=videos, repo_id=REPO_ID)
120
+
121
+ # Страница загрузки видео
122
+ @app.route('/upload', methods=['GET', 'POST'])
123
+ def upload视频():
124
+ if request.method == 'POST':
125
+ title = request.form.get('title')
126
+ description = request.form.get('description')
127
+ video_file = request.files.get('video')
128
+ uploader = "user1" # Можно добавить авторизацию позже
129
+
130
+ if not title or not video_file:
131
+ return "Укажите название и выберите видео", 400
132
+
133
+ filename = secure_filename(video_file.filename)
134
+ temp_path = os.path.join('uploads', filename)
135
+ os.makedirs('uploads', exist_ok=True)
136
+ video_file.save(temp_path)
137
+
138
+ # Загрузка на Hugging Face с прогрессом
139
+ api = HfApi()
140
+ api.upload_file(
141
+ path_or_fileobj=temp_path,
142
+ path_in_repo=f"videos/{filename}",
143
+ repo_id=REPO_ID,
144
+ repo_type="dataset",
145
+ token=HF_TOKEN_WRITE,
146
+ commit_message=f"Добавлено видео: {title}"
147
+ )
148
+
149
+ # Обновление базы данных
150
+ data = load_data()
151
+ video_id = f"video_{len(data['videos']) + 1}"
152
+ data['videos'].append({
153
+ 'id': video_id,
154
+ 'title': title,
155
+ 'description': description,
156
+ 'filename': filename,
157
+ 'uploader': uploader,
158
+ 'upload_date': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
159
+ })
160
+ save_data(data)
161
+
162
+ if os.path.exists(temp_path):
163
+ os.remove(temp_path)
164
+
165
+ return redirect(url_for('video_feed'))
166
+
167
+ html = '''
168
+ <!DOCTYPE html>
169
+ <html lang="ru">
170
+ <head>
171
+ <meta charset="UTF-8">
172
+ <title>Загрузка видео</title>
173
+ <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet">
174
+ <style>
175
+ body { font-family: 'Poppins', sans-serif; background: #f0f2f5; padding: 20px; }
176
+ .container { max-width: 600px; margin: 0 auto; background: #fff; padding: 20px; border-radius: 10px; box-shadow: 0 4px 15px rgba(0,0,0,0.1); }
177
+ input, textarea { width: 100%; padding: 10px; margin: 10px 0; border: 1px solid #e2e8f0; border-radius: 8px; }
178
+ button { padding: 10px 20px; background: #3b82f6; color: white; border: none; border-radius: 8px; cursor: pointer; }
179
+ #progress-container { margin-top: 10px; }
180
+ #progress-bar { width: 0%; height: 20px; background: #3b82f6; border-radius: 8px; transition: width 0.3s; }
181
+ </style>
182
+ </head>
183
+ <body>
184
+ <div class="container">
185
+ <h1>Загрузить видео</h1>
186
+ <form id="upload-form" enctype="multipart/form-data">
187
+ <input type="text" name="title" placeholder="Название видео" required>
188
+ <textarea name="description" placeholder="Описание" rows="4"></textarea>
189
+ <input type="file" name="video" accept="video/*" required>
190
+ <button type="submit">Загрузить</button>
191
+ </form>
192
+ <div id="progress-container">
193
+ <div id="progress-bar"></div>
194
+ <span id="progress-text">0%</span>
195
+ </div>
196
+ </div>
197
+ <script>
198
+ document.getElementById('upload-form').onsubmit = async function(e) {
199
+ e.preventDefault();
200
+ const formData = new FormData(this);
201
+ const progressBar = document.getElementById('progress-bar');
202
+ const progressText = document.getElementById('progress-text');
203
+ progressBar.style.display = 'block';
204
+
205
+ const xhr = new XMLHttpRequest();
206
+ xhr.open('POST', '/upload', true);
207
+
208
+ xhr.upload.onprogress = function(event) {
209
+ if (event.lengthComputable) {
210
+ const percent = Math.round((event.loaded / event.total) * 100);
211
+ progressBar.style.width = percent + '%';
212
+ progressText.textContent = percent + '%';
213
+ }
214
+ };
215
+
216
+ xhr.onload = function() {
217
+ if (xhr.status === 200) {
218
+ window.location = '/';
219
+ } else {
220
+ alert('Ошибка загрузки');
221
+ }
222
+ };
223
+
224
+ xhr.send(formData);
225
+ };
226
+ </script>
227
+ </body>
228
+ </html>
229
+ '''
230
+ return render_template_string(html)
231
+
232
+ if __name__ == '__main__':
233
+ backup_thread = threading.Thread(target=periodic_backup, daemon=True)
234
+ backup_thread.start()
235
+ app.run(debug=True, host='0.0.0.0', port=7860)