Update app.py
Browse files
app.py
CHANGED
|
@@ -18,7 +18,6 @@ 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 |
REGISTRATION_CODE = "morshenalphacl"
|
| 21 |
-
ADMIN_PASSWORD = "admin123" # Установите надежный пароль для админ-панели
|
| 22 |
|
| 23 |
cache = Cache(app, config={'CACHE_TYPE': 'simple'})
|
| 24 |
logging.basicConfig(level=logging.INFO)
|
|
@@ -145,6 +144,14 @@ h1 {
|
|
| 145 |
-webkit-background-clip: text;
|
| 146 |
color: transparent;
|
| 147 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 148 |
input, textarea {
|
| 149 |
width: 100%;
|
| 150 |
padding: 14px;
|
|
@@ -183,41 +190,39 @@ input:focus, textarea:focus {
|
|
| 183 |
}
|
| 184 |
.download-btn {
|
| 185 |
background: var(--secondary);
|
| 186 |
-
color: #ffffff;
|
| 187 |
margin-top: 10px;
|
| 188 |
}
|
| 189 |
.download-btn:hover {
|
| 190 |
background: #00b8c5;
|
| 191 |
-
color: #ffffff;
|
| 192 |
}
|
| 193 |
.delete-btn {
|
| 194 |
background: var(--delete-color);
|
| 195 |
-
color: #ffffff;
|
| 196 |
margin-top: 10px;
|
| 197 |
}
|
| 198 |
.delete-btn:hover {
|
| 199 |
background: #cc3333;
|
| 200 |
-
color: #ffffff;
|
| 201 |
}
|
| 202 |
.flash {
|
| 203 |
color: var(--secondary);
|
| 204 |
text-align: center;
|
| 205 |
margin-bottom: 15px;
|
| 206 |
}
|
| 207 |
-
.file-grid
|
| 208 |
display: grid;
|
| 209 |
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
| 210 |
gap: 20px;
|
| 211 |
margin-top: 20px;
|
| 212 |
}
|
|
|
|
|
|
|
|
|
|
| 213 |
.user-item {
|
| 214 |
-
background: var(--card-bg);
|
| 215 |
padding: 15px;
|
|
|
|
| 216 |
border-radius: 16px;
|
|
|
|
| 217 |
box-shadow: var(--shadow);
|
| 218 |
-
text-align: center;
|
| 219 |
transition: var(--transition);
|
| 220 |
-
cursor: pointer;
|
| 221 |
}
|
| 222 |
body.dark .user-item {
|
| 223 |
background: var(--card-bg-dark);
|
|
@@ -225,6 +230,24 @@ body.dark .user-item {
|
|
| 225 |
.user-item:hover {
|
| 226 |
transform: translateY(-5px);
|
| 227 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 228 |
.file-item {
|
| 229 |
background: var(--card-bg);
|
| 230 |
padding: 15px;
|
|
@@ -232,7 +255,6 @@ body.dark .user-item {
|
|
| 232 |
box-shadow: var(--shadow);
|
| 233 |
text-align: center;
|
| 234 |
transition: var(--transition);
|
| 235 |
-
display: none; /* Скрыто по умолчанию */
|
| 236 |
}
|
| 237 |
body.dark .file-item {
|
| 238 |
background: var(--card-bg-dark);
|
|
@@ -248,15 +270,15 @@ body.dark .file-item {
|
|
| 248 |
margin-bottom: 10px;
|
| 249 |
loading: lazy;
|
| 250 |
}
|
| 251 |
-
.file-item p
|
| 252 |
font-size: 0.9em;
|
| 253 |
margin: 5px 0;
|
| 254 |
}
|
| 255 |
-
.file-item a
|
| 256 |
color: var(--primary);
|
| 257 |
text-decoration: none;
|
| 258 |
}
|
| 259 |
-
.file-item a:hover
|
| 260 |
color: var(--accent);
|
| 261 |
}
|
| 262 |
.modal {
|
|
@@ -292,24 +314,6 @@ body.dark .file-item {
|
|
| 292 |
border-radius: 10px;
|
| 293 |
transition: width 0.3s ease;
|
| 294 |
}
|
| 295 |
-
#search-bar {
|
| 296 |
-
width: 100%;
|
| 297 |
-
padding: 10px;
|
| 298 |
-
margin: 10px 0;
|
| 299 |
-
border: none;
|
| 300 |
-
border-radius: 14px;
|
| 301 |
-
background: var(--glass-bg);
|
| 302 |
-
color: var(--text-light);
|
| 303 |
-
font-size: 1.1em;
|
| 304 |
-
box-shadow: inset 0 3px 10px rgba(0, 0, 0, 0.1);
|
| 305 |
-
}
|
| 306 |
-
body.dark #search-bar {
|
| 307 |
-
color: var(--text-dark);
|
| 308 |
-
}
|
| 309 |
-
#search-bar:focus {
|
| 310 |
-
outline: none;
|
| 311 |
-
box-shadow: 0 0 0 4px var(--primary);
|
| 312 |
-
}
|
| 313 |
'''
|
| 314 |
|
| 315 |
@app.route('/register', methods=['GET', 'POST'])
|
|
@@ -417,9 +421,9 @@ def login():
|
|
| 417 |
<button type="submit" class="btn">Войти</button>
|
| 418 |
</form>
|
| 419 |
<p style="margin-top: 20px;">Нет аккаунта? <a href="{{ url_for('register') }}">Зарегистрируйтесь</a></p>
|
| 420 |
-
<p style="margin-top: 10px;"><a href="{{ url_for('admhosto') }}">Админ-панель</a></p>
|
| 421 |
</div>
|
| 422 |
<script>
|
|
|
|
| 423 |
const savedCredentials = JSON.parse(localStorage.getItem('zeusCredentials'));
|
| 424 |
if (savedCredentials) {
|
| 425 |
fetch('/', {
|
|
@@ -438,6 +442,7 @@ def login():
|
|
| 438 |
.catch(error => console.error('Ошибка автоматического входа:', error));
|
| 439 |
}
|
| 440 |
|
|
|
|
| 441 |
document.getElementById('login-form').addEventListener('submit', function(e) {
|
| 442 |
e.preventDefault();
|
| 443 |
const formData = new FormData(this);
|
|
@@ -647,6 +652,7 @@ def dashboard():
|
|
| 647 |
xhr.send(formData);
|
| 648 |
});
|
| 649 |
|
|
|
|
| 650 |
document.getElementById('logout-btn').addEventListener('click', function(e) {
|
| 651 |
e.preventDefault();
|
| 652 |
localStorage.removeItem('zeusCredentials');
|
|
@@ -729,18 +735,18 @@ def delete_file(file_path):
|
|
| 729 |
|
| 730 |
return redirect(url_for('dashboard'))
|
| 731 |
|
| 732 |
-
@app.route('/
|
| 733 |
-
def
|
| 734 |
-
|
| 735 |
-
|
| 736 |
-
if admin_password != ADMIN_PASSWORD:
|
| 737 |
-
flash('Неверный пароль администратора!')
|
| 738 |
-
return redirect(url_for('admhosto'))
|
| 739 |
-
session['is_admin'] = True
|
| 740 |
-
return redirect(url_for('admhosto'))
|
| 741 |
|
| 742 |
-
|
| 743 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 744 |
<!DOCTYPE html>
|
| 745 |
<html lang="en">
|
| 746 |
<head>
|
|
@@ -753,39 +759,47 @@ def admhosto():
|
|
| 753 |
<body>
|
| 754 |
<div class="container">
|
| 755 |
<h1>Админ-панель Zeus Cloud</h1>
|
| 756 |
-
|
| 757 |
-
|
| 758 |
-
|
| 759 |
-
|
| 760 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 761 |
{% endif %}
|
| 762 |
-
|
| 763 |
-
<form method="POST">
|
| 764 |
-
<input type="password" name="admin_password" placeholder="Введите пароль администратора" required>
|
| 765 |
-
<button type="submit" class="btn">Войти</button>
|
| 766 |
-
</form>
|
| 767 |
</div>
|
| 768 |
</body>
|
| 769 |
</html>
|
| 770 |
'''
|
| 771 |
-
|
| 772 |
|
|
|
|
|
|
|
| 773 |
data = load_data()
|
| 774 |
-
|
| 775 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 776 |
html = '''
|
| 777 |
<!DOCTYPE html>
|
| 778 |
<html lang="en">
|
| 779 |
<head>
|
| 780 |
<meta charset="UTF-8">
|
| 781 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 782 |
-
<title
|
| 783 |
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;800&display=swap" rel="stylesheet">
|
| 784 |
<style>''' + BASE_STYLE + '''</style>
|
| 785 |
</head>
|
| 786 |
<body>
|
| 787 |
<div class="container">
|
| 788 |
-
<h1
|
| 789 |
{% with messages = get_flashed_messages() %}
|
| 790 |
{% if messages %}
|
| 791 |
{% for message in messages %}
|
|
@@ -793,74 +807,54 @@ def admhosto():
|
|
| 793 |
{% endfor %}
|
| 794 |
{% endif %}
|
| 795 |
{% endwith %}
|
| 796 |
-
<
|
| 797 |
-
|
| 798 |
-
|
| 799 |
-
|
| 800 |
-
|
| 801 |
-
|
| 802 |
-
|
| 803 |
-
|
| 804 |
-
|
| 805 |
-
|
| 806 |
-
|
| 807 |
-
<p>{{ file['filename'] }} (Video)</p>
|
| 808 |
-
{% elif file['type'] == 'image' %}
|
| 809 |
-
<p>{{ file['filename'] }} (Image)</p>
|
| 810 |
-
{% else %}
|
| 811 |
-
<p>{{ file['filename'] }}</p>
|
| 812 |
-
{% endif %}
|
| 813 |
-
<p>{{ file['upload_date'] }}</p>
|
| 814 |
-
</div>
|
| 815 |
-
{% endfor %}
|
| 816 |
-
{% if not users[username]['files'] %}
|
| 817 |
-
<p>Нет файлов</p>
|
| 818 |
{% endif %}
|
|
|
|
|
|
|
| 819 |
</div>
|
| 820 |
{% endfor %}
|
|
|
|
|
|
|
|
|
|
| 821 |
</div>
|
| 822 |
-
<a href="{{ url_for('
|
|
|
|
|
|
|
|
|
|
| 823 |
</div>
|
| 824 |
<script>
|
| 825 |
-
function
|
| 826 |
-
const
|
| 827 |
-
|
| 828 |
-
|
|
|
|
| 829 |
} else {
|
| 830 |
-
|
| 831 |
}
|
|
|
|
| 832 |
}
|
| 833 |
-
|
| 834 |
-
|
| 835 |
-
|
| 836 |
-
|
| 837 |
-
|
| 838 |
-
for (let i = 0; i < userItems.length; i++) {
|
| 839 |
-
const username = userItems[i].getElementsByTagName('p')[0].textContent.toLowerCase().replace('Пользователь: ', '');
|
| 840 |
-
if (username.includes(input)) {
|
| 841 |
-
userItems[i].style.display = '';
|
| 842 |
-
userItems[i].nextElementSibling.style.display = 'none'; // Скрываем файлы при поиске
|
| 843 |
-
} else {
|
| 844 |
-
userItems[i].style.display = 'none';
|
| 845 |
-
userItems[i].nextElementSibling.style.display = 'none';
|
| 846 |
-
}
|
| 847 |
}
|
| 848 |
}
|
| 849 |
</script>
|
| 850 |
</body>
|
| 851 |
</html>
|
| 852 |
'''
|
| 853 |
-
return render_template_string(html,
|
| 854 |
-
|
| 855 |
-
@app.route('/logout_admin')
|
| 856 |
-
def logout_admin():
|
| 857 |
-
session.pop('is_admin', None)
|
| 858 |
-
return redirect(url_for('admhosto'))
|
| 859 |
-
|
| 860 |
-
@app.route('/logout')
|
| 861 |
-
def logout():
|
| 862 |
-
session.pop('username', None)
|
| 863 |
-
return redirect(url_for('login'))
|
| 864 |
|
| 865 |
if __name__ == '__main__':
|
| 866 |
threading.Thread(target=periodic_backup, daemon=True).start()
|
|
|
|
| 18 |
HF_TOKEN_WRITE = os.getenv("HF_TOKEN")
|
| 19 |
HF_TOKEN_READ = os.getenv("HF_TOKEN_READ") or HF_TOKEN_WRITE
|
| 20 |
REGISTRATION_CODE = "morshenalphacl"
|
|
|
|
| 21 |
|
| 22 |
cache = Cache(app, config={'CACHE_TYPE': 'simple'})
|
| 23 |
logging.basicConfig(level=logging.INFO)
|
|
|
|
| 144 |
-webkit-background-clip: text;
|
| 145 |
color: transparent;
|
| 146 |
}
|
| 147 |
+
h2 {
|
| 148 |
+
font-size: 1.5em;
|
| 149 |
+
margin-top: 30px;
|
| 150 |
+
color: var(--text-light);
|
| 151 |
+
}
|
| 152 |
+
body.dark h2 {
|
| 153 |
+
color: var(--text-dark);
|
| 154 |
+
}
|
| 155 |
input, textarea {
|
| 156 |
width: 100%;
|
| 157 |
padding: 14px;
|
|
|
|
| 190 |
}
|
| 191 |
.download-btn {
|
| 192 |
background: var(--secondary);
|
|
|
|
| 193 |
margin-top: 10px;
|
| 194 |
}
|
| 195 |
.download-btn:hover {
|
| 196 |
background: #00b8c5;
|
|
|
|
| 197 |
}
|
| 198 |
.delete-btn {
|
| 199 |
background: var(--delete-color);
|
|
|
|
| 200 |
margin-top: 10px;
|
| 201 |
}
|
| 202 |
.delete-btn:hover {
|
| 203 |
background: #cc3333;
|
|
|
|
| 204 |
}
|
| 205 |
.flash {
|
| 206 |
color: var(--secondary);
|
| 207 |
text-align: center;
|
| 208 |
margin-bottom: 15px;
|
| 209 |
}
|
| 210 |
+
.file-grid {
|
| 211 |
display: grid;
|
| 212 |
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
| 213 |
gap: 20px;
|
| 214 |
margin-top: 20px;
|
| 215 |
}
|
| 216 |
+
.user-list {
|
| 217 |
+
margin-top: 20px;
|
| 218 |
+
}
|
| 219 |
.user-item {
|
|
|
|
| 220 |
padding: 15px;
|
| 221 |
+
background: var(--card-bg);
|
| 222 |
border-radius: 16px;
|
| 223 |
+
margin-bottom: 10px;
|
| 224 |
box-shadow: var(--shadow);
|
|
|
|
| 225 |
transition: var(--transition);
|
|
|
|
| 226 |
}
|
| 227 |
body.dark .user-item {
|
| 228 |
background: var(--card-bg-dark);
|
|
|
|
| 230 |
.user-item:hover {
|
| 231 |
transform: translateY(-5px);
|
| 232 |
}
|
| 233 |
+
.user-item a {
|
| 234 |
+
color: var(--primary);
|
| 235 |
+
text-decoration: none;
|
| 236 |
+
font-weight: 600;
|
| 237 |
+
}
|
| 238 |
+
.user-item a:hover {
|
| 239 |
+
color: var(--accent);
|
| 240 |
+
}
|
| 241 |
+
@media (max-width: 768px) {
|
| 242 |
+
.file-grid {
|
| 243 |
+
grid-template-columns: repeat(2, 1fr);
|
| 244 |
+
}
|
| 245 |
+
}
|
| 246 |
+
@media (max-width: 480px) {
|
| 247 |
+
.file-grid {
|
| 248 |
+
grid-template-columns: 1fr;
|
| 249 |
+
}
|
| 250 |
+
}
|
| 251 |
.file-item {
|
| 252 |
background: var(--card-bg);
|
| 253 |
padding: 15px;
|
|
|
|
| 255 |
box-shadow: var(--shadow);
|
| 256 |
text-align: center;
|
| 257 |
transition: var(--transition);
|
|
|
|
| 258 |
}
|
| 259 |
body.dark .file-item {
|
| 260 |
background: var(--card-bg-dark);
|
|
|
|
| 270 |
margin-bottom: 10px;
|
| 271 |
loading: lazy;
|
| 272 |
}
|
| 273 |
+
.file-item p {
|
| 274 |
font-size: 0.9em;
|
| 275 |
margin: 5px 0;
|
| 276 |
}
|
| 277 |
+
.file-item a {
|
| 278 |
color: var(--primary);
|
| 279 |
text-decoration: none;
|
| 280 |
}
|
| 281 |
+
.file-item a:hover {
|
| 282 |
color: var(--accent);
|
| 283 |
}
|
| 284 |
.modal {
|
|
|
|
| 314 |
border-radius: 10px;
|
| 315 |
transition: width 0.3s ease;
|
| 316 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 317 |
'''
|
| 318 |
|
| 319 |
@app.route('/register', methods=['GET', 'POST'])
|
|
|
|
| 421 |
<button type="submit" class="btn">Войти</button>
|
| 422 |
</form>
|
| 423 |
<p style="margin-top: 20px;">Нет аккаунта? <a href="{{ url_for('register') }}">Зарегистрируйтесь</a></p>
|
|
|
|
| 424 |
</div>
|
| 425 |
<script>
|
| 426 |
+
// Проверка localStorage и автоматический вход
|
| 427 |
const savedCredentials = JSON.parse(localStorage.getItem('zeusCredentials'));
|
| 428 |
if (savedCredentials) {
|
| 429 |
fetch('/', {
|
|
|
|
| 442 |
.catch(error => console.error('Ошибка автоматического входа:', error));
|
| 443 |
}
|
| 444 |
|
| 445 |
+
// Обработка формы входа
|
| 446 |
document.getElementById('login-form').addEventListener('submit', function(e) {
|
| 447 |
e.preventDefault();
|
| 448 |
const formData = new FormData(this);
|
|
|
|
| 652 |
xhr.send(formData);
|
| 653 |
});
|
| 654 |
|
| 655 |
+
// Обработка выхода
|
| 656 |
document.getElementById('logout-btn').addEventListener('click', function(e) {
|
| 657 |
e.preventDefault();
|
| 658 |
localStorage.removeItem('zeusCredentials');
|
|
|
|
| 735 |
|
| 736 |
return redirect(url_for('dashboard'))
|
| 737 |
|
| 738 |
+
@app.route('/logout')
|
| 739 |
+
def logout():
|
| 740 |
+
session.pop('username', None)
|
| 741 |
+
return redirect(url_for('login'))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 742 |
|
| 743 |
+
# Новая админ-панель
|
| 744 |
+
@app.route('/admhosto')
|
| 745 |
+
def admin_panel():
|
| 746 |
+
data = load_data()
|
| 747 |
+
users = data['users']
|
| 748 |
+
|
| 749 |
+
html = '''
|
| 750 |
<!DOCTYPE html>
|
| 751 |
<html lang="en">
|
| 752 |
<head>
|
|
|
|
| 759 |
<body>
|
| 760 |
<div class="container">
|
| 761 |
<h1>Админ-панель Zeus Cloud</h1>
|
| 762 |
+
<h2>Список пользователей</h2>
|
| 763 |
+
<div class="user-list">
|
| 764 |
+
{% for username, user_data in users.items() %}
|
| 765 |
+
<div class="user-item">
|
| 766 |
+
<a href="{{ url_for('admin_user_files', username=username) }}">{{ username }}</a>
|
| 767 |
+
<p>Дата регистрации: {{ user_data['created_at'] }}</p>
|
| 768 |
+
<p>Количество файлов: {{ user_data['files'] | length }}</p>
|
| 769 |
+
</div>
|
| 770 |
+
{% endfor %}
|
| 771 |
+
{% if not users %}
|
| 772 |
+
<p>Пользователей пока нет.</p>
|
| 773 |
{% endif %}
|
| 774 |
+
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 775 |
</div>
|
| 776 |
</body>
|
| 777 |
</html>
|
| 778 |
'''
|
| 779 |
+
return render_template_string(html, users=users)
|
| 780 |
|
| 781 |
+
@app.route('/admhosto/user/<username>')
|
| 782 |
+
def admin_user_files(username):
|
| 783 |
data = load_data()
|
| 784 |
+
if username not in data['users']:
|
| 785 |
+
flash('Пользователь не найден!')
|
| 786 |
+
return redirect(url_for('admin_panel'))
|
| 787 |
+
|
| 788 |
+
user_files = sorted(data['users'][username]['files'], key=lambda x: x['upload_date'], reverse=True)
|
| 789 |
+
|
| 790 |
html = '''
|
| 791 |
<!DOCTYPE html>
|
| 792 |
<html lang="en">
|
| 793 |
<head>
|
| 794 |
<meta charset="UTF-8">
|
| 795 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 796 |
+
<title>Файлы пользователя {{ username }} - Zeus Cloud</title>
|
| 797 |
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;800&display=swap" rel="stylesheet">
|
| 798 |
<style>''' + BASE_STYLE + '''</style>
|
| 799 |
</head>
|
| 800 |
<body>
|
| 801 |
<div class="container">
|
| 802 |
+
<h1>Файлы пользователя: {{ username }}</h1>
|
| 803 |
{% with messages = get_flashed_messages() %}
|
| 804 |
{% if messages %}
|
| 805 |
{% for message in messages %}
|
|
|
|
| 807 |
{% endfor %}
|
| 808 |
{% endif %}
|
| 809 |
{% endwith %}
|
| 810 |
+
<div class="file-grid">
|
| 811 |
+
{% for file in user_files %}
|
| 812 |
+
<div class="file-item">
|
| 813 |
+
{% if file['type'] == 'video' %}
|
| 814 |
+
<video class="file-preview" preload="metadata" muted loading="lazy" onclick="openModal('https://huggingface.co/datasets/{{ repo_id }}/resolve/main/{{ file['path'] }}', true)">
|
| 815 |
+
<source src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/{{ file['path'] }}" type="video/mp4">
|
| 816 |
+
</video>
|
| 817 |
+
{% elif file['type'] == 'image' %}
|
| 818 |
+
<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)">
|
| 819 |
+
{% else %}
|
| 820 |
+
<p>{{ file['filename'] }}</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 821 |
{% endif %}
|
| 822 |
+
<p>{{ file['upload_date'] }}</p>
|
| 823 |
+
<a href="{{ url_for('download_file', file_path=file['path'], filename=file['filename']) }}" class="btn download-btn">Скачать</a>
|
| 824 |
</div>
|
| 825 |
{% endfor %}
|
| 826 |
+
{% if not user_files %}
|
| 827 |
+
<p>У пользователя пока нет файлов.</p>
|
| 828 |
+
{% endif %}
|
| 829 |
</div>
|
| 830 |
+
<a href="{{ url_for('admin_panel') }}" class="btn" style="margin-top: 20px;">Назад к списку пользователей</a>
|
| 831 |
+
</div>
|
| 832 |
+
<div class="modal" id="mediaModal" onclick="closeModal(event)">
|
| 833 |
+
<div id="modalContent"></div>
|
| 834 |
</div>
|
| 835 |
<script>
|
| 836 |
+
function openModal(src, isVideo) {
|
| 837 |
+
const modal = document.getElementById('mediaModal');
|
| 838 |
+
const modalContent = document.getElementById('modalContent');
|
| 839 |
+
if (isVideo) {
|
| 840 |
+
modalContent.innerHTML = `<video controls><source src="${src}" type="video/mp4"></video>`;
|
| 841 |
} else {
|
| 842 |
+
modalContent.innerHTML = `<img src="${src}">`;
|
| 843 |
}
|
| 844 |
+
modal.style.display = 'flex';
|
| 845 |
}
|
| 846 |
+
function closeModal(event) {
|
| 847 |
+
if (event.target.tagName !== 'IMG' && event.target.tagName !== 'VIDEO') {
|
| 848 |
+
const modal = document.getElementById('mediaModal');
|
| 849 |
+
modal.style.display = 'none';
|
| 850 |
+
modal.innerHTML = '<div id="modalContent"></div>';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 851 |
}
|
| 852 |
}
|
| 853 |
</script>
|
| 854 |
</body>
|
| 855 |
</html>
|
| 856 |
'''
|
| 857 |
+
return render_template_string(html, username=username, user_files=user_files, repo_id=REPO_ID)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 858 |
|
| 859 |
if __name__ == '__main__':
|
| 860 |
threading.Thread(target=periodic_backup, daemon=True).start()
|