Update app.py
Browse files
app.py
CHANGED
|
@@ -208,7 +208,7 @@ BASE_STYLE = '''
|
|
| 208 |
transform: scale(1.08);
|
| 209 |
background: #5439cc;
|
| 210 |
}
|
| 211 |
-
input, textarea {
|
| 212 |
width: 100%;
|
| 213 |
padding: 14px;
|
| 214 |
margin: 15px 0;
|
|
@@ -219,11 +219,11 @@ BASE_STYLE = '''
|
|
| 219 |
font-size: 1.1em;
|
| 220 |
transition: var(--transition);
|
| 221 |
}
|
| 222 |
-
body.dark input, body.dark textarea {
|
| 223 |
border: 2px solid rgba(255, 255, 255, 0.1);
|
| 224 |
color: var(--text-dark);
|
| 225 |
}
|
| 226 |
-
input:focus, textarea:focus {
|
| 227 |
outline: none;
|
| 228 |
border-color: var(--primary);
|
| 229 |
background: rgba(255, 255, 255, 0.2);
|
|
@@ -279,7 +279,7 @@ BASE_STYLE = '''
|
|
| 279 |
top: 80px;
|
| 280 |
right: 15px;
|
| 281 |
}
|
| 282 |
-
.btn, input, textarea {
|
| 283 |
font-size: 1em;
|
| 284 |
padding: 12px;
|
| 285 |
}
|
|
@@ -695,6 +695,10 @@ def feed():
|
|
| 695 |
.username-link:hover {
|
| 696 |
text-decoration: underline;
|
| 697 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 698 |
</style>
|
| 699 |
</head>
|
| 700 |
<body>
|
|
@@ -712,15 +716,12 @@ def feed():
|
|
| 712 |
<div class="post-grid">
|
| 713 |
{% for post in posts %}
|
| 714 |
<a href="{{ url_for('post_page', post_id=post['id']) }}" class="post-item">
|
| 715 |
-
|
| 716 |
-
<
|
| 717 |
-
|
| 718 |
-
</video>
|
| 719 |
-
{% else %}
|
| 720 |
-
<img class="post-preview" src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/{{ post['type'] }}s/{{ post['filename'] }}" alt="{{ post['title'] }}" onclick="openModal(this.src, event)">
|
| 721 |
-
{% endif %}
|
| 722 |
<h2>{{ post['title'] }}</h2>
|
| 723 |
<p>{{ post['description'] }}</p>
|
|
|
|
| 724 |
<p>Загрузил: <a href="{{ url_for('user_profile', username=post['uploader']) }}" class="username-link">{{ post['uploader'] }}</a> | {{ post['upload_date'] }}</p>
|
| 725 |
<p class="stats">Просмотров: {{ post['views'] }} | Лайков: {{ post['likes']|length }}</p>
|
| 726 |
</a>
|
|
@@ -754,11 +755,9 @@ def feed():
|
|
| 754 |
if (localStorage.getItem('theme') === 'dark') document.body.classList.add('dark');
|
| 755 |
const videos = document.querySelectorAll('.post-preview');
|
| 756 |
videos.forEach(video => {
|
| 757 |
-
|
| 758 |
-
video.
|
| 759 |
-
|
| 760 |
-
});
|
| 761 |
-
}
|
| 762 |
});
|
| 763 |
};
|
| 764 |
</script>
|
|
@@ -822,7 +821,7 @@ def post_page(post_id):
|
|
| 822 |
-webkit-background-clip: text;
|
| 823 |
color: transparent;
|
| 824 |
}
|
| 825 |
-
video
|
| 826 |
width: 100%;
|
| 827 |
max-height: 500px;
|
| 828 |
object-fit: cover;
|
|
@@ -858,6 +857,10 @@ def post_page(post_id):
|
|
| 858 |
.username-link:hover {
|
| 859 |
text-decoration: underline;
|
| 860 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 861 |
</style>
|
| 862 |
</head>
|
| 863 |
<body>
|
|
@@ -866,14 +869,11 @@ def post_page(post_id):
|
|
| 866 |
<button class="theme-toggle" onclick="toggleTheme()">🌙</button>
|
| 867 |
<div class="container">
|
| 868 |
<h1>{{ post['title'] }}</h1>
|
| 869 |
-
|
| 870 |
-
<video
|
| 871 |
-
|
| 872 |
-
</video>
|
| 873 |
-
{% else %}
|
| 874 |
-
<img src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/{{ post['type'] }}s/{{ post['filename'] }}" alt="{{ post['title'] }}" onclick="openModal(this.src)">
|
| 875 |
-
{% endif %}
|
| 876 |
<p>{{ post['description'] }}</p>
|
|
|
|
| 877 |
<p>Загрузил: <a href="{{ url_for('user_profile', username=post['uploader']) }}" class="username-link">{{ post['uploader'] }}</a> | {{ post['upload_date'] }}</p>
|
| 878 |
<p>Просмотров: {{ post['views'] }} | Лайков: {{ post['likes']|length }}</p>
|
| 879 |
{% if is_authenticated %}
|
|
@@ -898,9 +898,6 @@ def post_page(post_id):
|
|
| 898 |
<p style="margin-top: 20px;"><a href="{{ url_for('login') }}">Войдите</a>, чтобы ставить лайки и комментировать.</p>
|
| 899 |
{% endif %}
|
| 900 |
</div>
|
| 901 |
-
<div class="modal" id="imageModal" onclick="closeModal(event)">
|
| 902 |
-
<img id="modalImage" src="">
|
| 903 |
-
</div>
|
| 904 |
<script>
|
| 905 |
function toggleSidebar() {
|
| 906 |
document.getElementById('sidebar').classList.toggle('active');
|
|
@@ -909,17 +906,6 @@ def post_page(post_id):
|
|
| 909 |
document.body.classList.toggle('dark');
|
| 910 |
localStorage.setItem('theme', document.body.classList.contains('dark') ? 'dark' : 'light');
|
| 911 |
}
|
| 912 |
-
function openModal(src) {
|
| 913 |
-
const modal = document.getElementById('imageModal');
|
| 914 |
-
const modalImg = document.getElementById('modalImage');
|
| 915 |
-
modal.style.display = 'flex';
|
| 916 |
-
modalImg.src = src;
|
| 917 |
-
}
|
| 918 |
-
function closeModal(event) {
|
| 919 |
-
if (event.target.tagName !== 'IMG') {
|
| 920 |
-
document.getElementById('imageModal').style.display = 'none';
|
| 921 |
-
}
|
| 922 |
-
}
|
| 923 |
window.onload = () => {
|
| 924 |
if (localStorage.getItem('theme') === 'dark') document.body.classList.add('dark');
|
| 925 |
};
|
|
@@ -1079,6 +1065,10 @@ def profile():
|
|
| 1079 |
-webkit-background-clip: text;
|
| 1080 |
color: transparent;
|
| 1081 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1082 |
</style>
|
| 1083 |
</head>
|
| 1084 |
<body>
|
|
@@ -1109,24 +1099,21 @@ def profile():
|
|
| 1109 |
<button type="submit" name="update_profile" class="btn">Сохранить</button>
|
| 1110 |
</form>
|
| 1111 |
{% if user_type == 'seller' and verified %}
|
| 1112 |
-
<a href="{{ url_for('upload') }}" class="btn">Добавить
|
| 1113 |
{% endif %}
|
| 1114 |
-
<h2>Ваши
|
| 1115 |
<div class="post-grid">
|
| 1116 |
{% if user_posts %}
|
| 1117 |
{% for post in user_posts %}
|
| 1118 |
<div class="post-item">
|
| 1119 |
<a href="{{ url_for('post_page', post_id=post['id']) }}">
|
| 1120 |
-
|
| 1121 |
-
<
|
| 1122 |
-
|
| 1123 |
-
</video>
|
| 1124 |
-
{% else %}
|
| 1125 |
-
<img class="post-preview" src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/{{ post['type'] }}s/{{ post['filename'] }}" alt="{{ post['title'] }}" onclick="openModal(this.src, event)">
|
| 1126 |
-
{% endif %}
|
| 1127 |
<h3>{{ post['title'] }}</h3>
|
| 1128 |
</a>
|
| 1129 |
<p>{{ post['description'] }}</p>
|
|
|
|
| 1130 |
<p>{{ post['upload_date'] }}</p>
|
| 1131 |
<form method="POST">
|
| 1132 |
<input type="hidden" name="post_id" value="{{ post['id'] }}">
|
|
@@ -1135,13 +1122,10 @@ def profile():
|
|
| 1135 |
</div>
|
| 1136 |
{% endfor %}
|
| 1137 |
{% else %}
|
| 1138 |
-
<p style="font-size: 1.2em;">Вы пока не загрузили ни
|
| 1139 |
{% endif %}
|
| 1140 |
</div>
|
| 1141 |
</div>
|
| 1142 |
-
<div class="modal" id="imageModal" onclick="closeModal(event)">
|
| 1143 |
-
<img id="modalImage" src="">
|
| 1144 |
-
</div>
|
| 1145 |
<script>
|
| 1146 |
function toggleSidebar() {
|
| 1147 |
document.getElementById('sidebar').classList.toggle('active');
|
|
@@ -1150,18 +1134,6 @@ def profile():
|
|
| 1150 |
document.body.classList.toggle('dark');
|
| 1151 |
localStorage.setItem('theme', document.body.classList.contains('dark') ? 'dark' : 'light');
|
| 1152 |
}
|
| 1153 |
-
function openModal(src, event) {
|
| 1154 |
-
event.preventDefault();
|
| 1155 |
-
const modal = document.getElementById('imageModal');
|
| 1156 |
-
const modalImg = document.getElementById('modalImage');
|
| 1157 |
-
modal.style.display = 'flex';
|
| 1158 |
-
modalImg.src = src;
|
| 1159 |
-
}
|
| 1160 |
-
function closeModal(event) {
|
| 1161 |
-
if (event.target.tagName !== 'IMG') {
|
| 1162 |
-
document.getElementById('imageModal').style.display = 'none';
|
| 1163 |
-
}
|
| 1164 |
-
}
|
| 1165 |
function copyProfileLink() {
|
| 1166 |
navigator.clipboard.writeText(window.location.href).then(() => {
|
| 1167 |
alert('Ссылка скопирована!');
|
|
@@ -1171,11 +1143,9 @@ def profile():
|
|
| 1171 |
if (localStorage.getItem('theme') === 'dark') document.body.classList.add('dark');
|
| 1172 |
const videos = document.querySelectorAll('.post-preview');
|
| 1173 |
videos.forEach(video => {
|
| 1174 |
-
|
| 1175 |
-
video.
|
| 1176 |
-
|
| 1177 |
-
});
|
| 1178 |
-
}
|
| 1179 |
});
|
| 1180 |
};
|
| 1181 |
</script>
|
|
@@ -1291,6 +1261,10 @@ def user_profile(username):
|
|
| 1291 |
-webkit-background-clip: text;
|
| 1292 |
color: transparent;
|
| 1293 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1294 |
</style>
|
| 1295 |
</head>
|
| 1296 |
<body>
|
|
@@ -1313,33 +1287,27 @@ def user_profile(username):
|
|
| 1313 |
<button class="btn share-btn" onclick="copyProfileLink()">Поделиться</button>
|
| 1314 |
</div>
|
| 1315 |
</div>
|
| 1316 |
-
<h2
|
| 1317 |
<div class="post-grid">
|
| 1318 |
{% if user_posts %}
|
| 1319 |
{% for post in user_posts %}
|
| 1320 |
<div class="post-item">
|
| 1321 |
<a href="{{ url_for('post_page', post_id=post['id']) }}">
|
| 1322 |
-
|
| 1323 |
-
<
|
| 1324 |
-
|
| 1325 |
-
</video>
|
| 1326 |
-
{% else %}
|
| 1327 |
-
<img class="post-preview" src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/{{ post['type'] }}s/{{ post['filename'] }}" alt="{{ post['title'] }}" onclick="openModal(this.src, event)">
|
| 1328 |
-
{% endif %}
|
| 1329 |
<h3>{{ post['title'] }}</h3>
|
| 1330 |
</a>
|
| 1331 |
<p>{{ post['description'] }}</p>
|
|
|
|
| 1332 |
<p>{{ post['upload_date'] }}</p>
|
| 1333 |
</div>
|
| 1334 |
{% endfor %}
|
| 1335 |
{% else %}
|
| 1336 |
-
<p style="font-size: 1.2em;">Этот пользователь пока не загрузил ни
|
| 1337 |
{% endif %}
|
| 1338 |
</div>
|
| 1339 |
</div>
|
| 1340 |
-
<div class="modal" id="imageModal" onclick="closeModal(event)">
|
| 1341 |
-
<img id="modalImage" src="">
|
| 1342 |
-
</div>
|
| 1343 |
<script>
|
| 1344 |
function toggleSidebar() {
|
| 1345 |
document.getElementById('sidebar').classList.toggle('active');
|
|
@@ -1348,18 +1316,6 @@ def user_profile(username):
|
|
| 1348 |
document.body.classList.toggle('dark');
|
| 1349 |
localStorage.setItem('theme', document.body.classList.contains('dark') ? 'dark' : 'light');
|
| 1350 |
}
|
| 1351 |
-
function openModal(src, event) {
|
| 1352 |
-
event.preventDefault();
|
| 1353 |
-
const modal = document.getElementById('imageModal');
|
| 1354 |
-
const modalImg = document.getElementById('modalImage');
|
| 1355 |
-
modal.style.display = 'flex';
|
| 1356 |
-
modalImg.src = src;
|
| 1357 |
-
}
|
| 1358 |
-
function closeModal(event) {
|
| 1359 |
-
if (event.target.tagName !== 'IMG') {
|
| 1360 |
-
document.getElementById('imageModal').style.display = 'none';
|
| 1361 |
-
}
|
| 1362 |
-
}
|
| 1363 |
function copyProfileLink() {
|
| 1364 |
navigator.clipboard.writeText(window.location.href).then(() => {
|
| 1365 |
alert('Ссылка скопирована!');
|
|
@@ -1369,11 +1325,9 @@ def user_profile(username):
|
|
| 1369 |
if (localStorage.getItem('theme') === 'dark') document.body.classList.add('dark');
|
| 1370 |
const videos = document.querySelectorAll('.post-preview');
|
| 1371 |
videos.forEach(video => {
|
| 1372 |
-
|
| 1373 |
-
video.
|
| 1374 |
-
|
| 1375 |
-
});
|
| 1376 |
-
}
|
| 1377 |
});
|
| 1378 |
};
|
| 1379 |
</script>
|
|
@@ -1393,32 +1347,38 @@ def upload():
|
|
| 1393 |
username = session['username']
|
| 1394 |
user_data = data['users'].get(username, {})
|
| 1395 |
if user_data.get('type') != 'seller' or not user_data.get('verified'):
|
| 1396 |
-
flash('Только проверенные продавцы могут загружать
|
| 1397 |
return redirect(url_for('profile'))
|
| 1398 |
|
| 1399 |
if request.method == 'POST':
|
| 1400 |
title = request.form.get('title')
|
| 1401 |
description = request.form.get('description')
|
|
|
|
|
|
|
| 1402 |
file = request.files.get('file')
|
| 1403 |
uploader = session['username']
|
| 1404 |
|
| 1405 |
-
if not title or not file:
|
| 1406 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1407 |
|
| 1408 |
filename = secure_filename(file.filename)
|
| 1409 |
temp_path = os.path.join('uploads', filename)
|
| 1410 |
os.makedirs('uploads', exist_ok=True)
|
| 1411 |
file.save(temp_path)
|
| 1412 |
|
| 1413 |
-
file_type = 'video' if filename.lower().endswith(('.mp4', '.mov', '.avi')) else 'photo'
|
| 1414 |
api = HfApi()
|
| 1415 |
api.upload_file(
|
| 1416 |
path_or_fileobj=temp_path,
|
| 1417 |
-
path_in_repo=f"
|
| 1418 |
repo_id=REPO_ID,
|
| 1419 |
repo_type="dataset",
|
| 1420 |
token=HF_TOKEN_WRITE,
|
| 1421 |
-
commit_message=f"
|
| 1422 |
)
|
| 1423 |
|
| 1424 |
data = load_data()
|
|
@@ -1430,12 +1390,14 @@ def upload():
|
|
| 1430 |
'title': title,
|
| 1431 |
'description': description,
|
| 1432 |
'filename': filename,
|
| 1433 |
-
'type':
|
| 1434 |
'uploader': uploader,
|
| 1435 |
'upload_date': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
|
| 1436 |
'views': 0,
|
| 1437 |
'likes': [],
|
| 1438 |
-
'comments': []
|
|
|
|
|
|
|
| 1439 |
})
|
| 1440 |
save_data(data)
|
| 1441 |
|
|
@@ -1451,7 +1413,7 @@ def upload():
|
|
| 1451 |
<head>
|
| 1452 |
<meta charset="UTF-8">
|
| 1453 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 1454 |
-
<title>Загрузка
|
| 1455 |
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600&display=swap" rel="stylesheet">
|
| 1456 |
<style>
|
| 1457 |
''' + BASE_STYLE + '''
|
|
@@ -1491,6 +1453,13 @@ def upload():
|
|
| 1491 |
background: var(--primary);
|
| 1492 |
transition: width 0.4s ease;
|
| 1493 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1494 |
</style>
|
| 1495 |
</head>
|
| 1496 |
<body>
|
|
@@ -1498,11 +1467,28 @@ def upload():
|
|
| 1498 |
''' + NAV_HTML + '''
|
| 1499 |
<button class="theme-toggle" onclick="toggleTheme()">🌙</button>
|
| 1500 |
<div class="container">
|
| 1501 |
-
<h1>Загрузить
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1502 |
<form id="upload-form" enctype="multipart/form-data">
|
| 1503 |
<input type="text" name="title" placeholder="Название" required>
|
| 1504 |
<textarea name="description" placeholder="Описание" rows="5"></textarea>
|
| 1505 |
-
<input type="
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1506 |
<button type="submit" class="btn">Загрузить</button>
|
| 1507 |
</form>
|
| 1508 |
<div id="progress-container">
|
|
@@ -1691,6 +1677,10 @@ def admin_panel():
|
|
| 1691 |
.username-link:hover {
|
| 1692 |
text-decoration: underline;
|
| 1693 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1694 |
</style>
|
| 1695 |
</head>
|
| 1696 |
<body>
|
|
@@ -1720,7 +1710,7 @@ def admin_panel():
|
|
| 1720 |
<p style="font-size: 1.2em;">Нет организаций на проверке.</p>
|
| 1721 |
{% endif %}
|
| 1722 |
</div>
|
| 1723 |
-
<h2>Все
|
| 1724 |
<div class="search-container">
|
| 1725 |
<form method="GET">
|
| 1726 |
<input type="text" name="search" class="search-input" placeholder="Поиск по названию или описанию" value="{{ search_query }}">
|
|
@@ -1732,16 +1722,13 @@ def admin_panel():
|
|
| 1732 |
{% for post in posts %}
|
| 1733 |
<div class="post-item">
|
| 1734 |
<a href="{{ url_for('post_page', post_id=post['id']) }}">
|
| 1735 |
-
|
| 1736 |
-
<
|
| 1737 |
-
|
| 1738 |
-
</video>
|
| 1739 |
-
{% else %}
|
| 1740 |
-
<img class="post-preview" src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/{{ post['type'] }}s/{{ post['filename'] }}" alt="{{ post['title'] }}">
|
| 1741 |
-
{% endif %}
|
| 1742 |
<h3>{{ post['title'] }}</h3>
|
| 1743 |
</a>
|
| 1744 |
<p>{{ post['description'] }}</p>
|
|
|
|
| 1745 |
<p>Загрузил: <a href="{{ url_for('user_profile', username=post['uploader']) }}" class="username-link">{{ post['uploader'] }}</a> | {{ post['upload_date'] }}</p>
|
| 1746 |
<form method="POST">
|
| 1747 |
<input type="hidden" name="post_id" value="{{ post['id'] }}">
|
|
@@ -1750,7 +1737,7 @@ def admin_panel():
|
|
| 1750 |
</div>
|
| 1751 |
{% endfor %}
|
| 1752 |
{% else %}
|
| 1753 |
-
<p style="font-size: 1.2em;"
|
| 1754 |
{% endif %}
|
| 1755 |
</div>
|
| 1756 |
</div>
|
|
@@ -1766,11 +1753,9 @@ def admin_panel():
|
|
| 1766 |
if (localStorage.getItem('theme') === 'dark') document.body.classList.add('dark');
|
| 1767 |
const videos = document.querySelectorAll('.post-preview');
|
| 1768 |
videos.forEach(video => {
|
| 1769 |
-
|
| 1770 |
-
video.
|
| 1771 |
-
|
| 1772 |
-
});
|
| 1773 |
-
}
|
| 1774 |
});
|
| 1775 |
};
|
| 1776 |
</script>
|
|
|
|
| 208 |
transform: scale(1.08);
|
| 209 |
background: #5439cc;
|
| 210 |
}
|
| 211 |
+
input, textarea, select {
|
| 212 |
width: 100%;
|
| 213 |
padding: 14px;
|
| 214 |
margin: 15px 0;
|
|
|
|
| 219 |
font-size: 1.1em;
|
| 220 |
transition: var(--transition);
|
| 221 |
}
|
| 222 |
+
body.dark input, body.dark textarea, body.dark select {
|
| 223 |
border: 2px solid rgba(255, 255, 255, 0.1);
|
| 224 |
color: var(--text-dark);
|
| 225 |
}
|
| 226 |
+
input:focus, textarea:focus, select:focus {
|
| 227 |
outline: none;
|
| 228 |
border-color: var(--primary);
|
| 229 |
background: rgba(255, 255, 255, 0.2);
|
|
|
|
| 279 |
top: 80px;
|
| 280 |
right: 15px;
|
| 281 |
}
|
| 282 |
+
.btn, input, textarea, select {
|
| 283 |
font-size: 1em;
|
| 284 |
padding: 12px;
|
| 285 |
}
|
|
|
|
| 695 |
.username-link:hover {
|
| 696 |
text-decoration: underline;
|
| 697 |
}
|
| 698 |
+
.price {
|
| 699 |
+
font-weight: 600;
|
| 700 |
+
color: var(--primary);
|
| 701 |
+
}
|
| 702 |
</style>
|
| 703 |
</head>
|
| 704 |
<body>
|
|
|
|
| 716 |
<div class="post-grid">
|
| 717 |
{% for post in posts %}
|
| 718 |
<a href="{{ url_for('post_page', post_id=post['id']) }}" class="post-item">
|
| 719 |
+
<video class="post-preview" preload="metadata" muted>
|
| 720 |
+
<source src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/videos/{{ post['filename'] }}" type="video/mp4">
|
| 721 |
+
</video>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 722 |
<h2>{{ post['title'] }}</h2>
|
| 723 |
<p>{{ post['description'] }}</p>
|
| 724 |
+
<p class="price">Цена: {{ post['price'] }} {{ post['currency'] }}</p>
|
| 725 |
<p>Загрузил: <a href="{{ url_for('user_profile', username=post['uploader']) }}" class="username-link">{{ post['uploader'] }}</a> | {{ post['upload_date'] }}</p>
|
| 726 |
<p class="stats">Просмотров: {{ post['views'] }} | Лайков: {{ post['likes']|length }}</p>
|
| 727 |
</a>
|
|
|
|
| 755 |
if (localStorage.getItem('theme') === 'dark') document.body.classList.add('dark');
|
| 756 |
const videos = document.querySelectorAll('.post-preview');
|
| 757 |
videos.forEach(video => {
|
| 758 |
+
video.addEventListener('loadedmetadata', () => {
|
| 759 |
+
video.currentTime = Math.random() * video.duration;
|
| 760 |
+
});
|
|
|
|
|
|
|
| 761 |
});
|
| 762 |
};
|
| 763 |
</script>
|
|
|
|
| 821 |
-webkit-background-clip: text;
|
| 822 |
color: transparent;
|
| 823 |
}
|
| 824 |
+
video {
|
| 825 |
width: 100%;
|
| 826 |
max-height: 500px;
|
| 827 |
object-fit: cover;
|
|
|
|
| 857 |
.username-link:hover {
|
| 858 |
text-decoration: underline;
|
| 859 |
}
|
| 860 |
+
.price {
|
| 861 |
+
font-weight: 600;
|
| 862 |
+
color: var(--primary);
|
| 863 |
+
}
|
| 864 |
</style>
|
| 865 |
</head>
|
| 866 |
<body>
|
|
|
|
| 869 |
<button class="theme-toggle" onclick="toggleTheme()">🌙</button>
|
| 870 |
<div class="container">
|
| 871 |
<h1>{{ post['title'] }}</h1>
|
| 872 |
+
<video controls>
|
| 873 |
+
<source src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/videos/{{ post['filename'] }}" type="video/mp4">
|
| 874 |
+
</video>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 875 |
<p>{{ post['description'] }}</p>
|
| 876 |
+
<p class="price">Цена: {{ post['price'] }} {{ post['currency'] }}</p>
|
| 877 |
<p>Загрузил: <a href="{{ url_for('user_profile', username=post['uploader']) }}" class="username-link">{{ post['uploader'] }}</a> | {{ post['upload_date'] }}</p>
|
| 878 |
<p>Просмотров: {{ post['views'] }} | Лайков: {{ post['likes']|length }}</p>
|
| 879 |
{% if is_authenticated %}
|
|
|
|
| 898 |
<p style="margin-top: 20px;"><a href="{{ url_for('login') }}">Войдите</a>, чтобы ставить лайки и комментировать.</p>
|
| 899 |
{% endif %}
|
| 900 |
</div>
|
|
|
|
|
|
|
|
|
|
| 901 |
<script>
|
| 902 |
function toggleSidebar() {
|
| 903 |
document.getElementById('sidebar').classList.toggle('active');
|
|
|
|
| 906 |
document.body.classList.toggle('dark');
|
| 907 |
localStorage.setItem('theme', document.body.classList.contains('dark') ? 'dark' : 'light');
|
| 908 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 909 |
window.onload = () => {
|
| 910 |
if (localStorage.getItem('theme') === 'dark') document.body.classList.add('dark');
|
| 911 |
};
|
|
|
|
| 1065 |
-webkit-background-clip: text;
|
| 1066 |
color: transparent;
|
| 1067 |
}
|
| 1068 |
+
.price {
|
| 1069 |
+
font-weight: 600;
|
| 1070 |
+
color: var(--primary);
|
| 1071 |
+
}
|
| 1072 |
</style>
|
| 1073 |
</head>
|
| 1074 |
<body>
|
|
|
|
| 1099 |
<button type="submit" name="update_profile" class="btn">Сохранить</button>
|
| 1100 |
</form>
|
| 1101 |
{% if user_type == 'seller' and verified %}
|
| 1102 |
+
<a href="{{ url_for('upload') }}" class="btn">Добавить видео</a>
|
| 1103 |
{% endif %}
|
| 1104 |
+
<h2>Ваши видео</h2>
|
| 1105 |
<div class="post-grid">
|
| 1106 |
{% if user_posts %}
|
| 1107 |
{% for post in user_posts %}
|
| 1108 |
<div class="post-item">
|
| 1109 |
<a href="{{ url_for('post_page', post_id=post['id']) }}">
|
| 1110 |
+
<video class="post-preview" preload="metadata" muted>
|
| 1111 |
+
<source src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/videos/{{ post['filename'] }}" type="video/mp4">
|
| 1112 |
+
</video>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1113 |
<h3>{{ post['title'] }}</h3>
|
| 1114 |
</a>
|
| 1115 |
<p>{{ post['description'] }}</p>
|
| 1116 |
+
<p class="price">Цена: {{ post['price'] }} {{ post['currency'] }}</p>
|
| 1117 |
<p>{{ post['upload_date'] }}</p>
|
| 1118 |
<form method="POST">
|
| 1119 |
<input type="hidden" name="post_id" value="{{ post['id'] }}">
|
|
|
|
| 1122 |
</div>
|
| 1123 |
{% endfor %}
|
| 1124 |
{% else %}
|
| 1125 |
+
<p style="font-size: 1.2em;">Вы пока не загрузили ни одного видео.</p>
|
| 1126 |
{% endif %}
|
| 1127 |
</div>
|
| 1128 |
</div>
|
|
|
|
|
|
|
|
|
|
| 1129 |
<script>
|
| 1130 |
function toggleSidebar() {
|
| 1131 |
document.getElementById('sidebar').classList.toggle('active');
|
|
|
|
| 1134 |
document.body.classList.toggle('dark');
|
| 1135 |
localStorage.setItem('theme', document.body.classList.contains('dark') ? 'dark' : 'light');
|
| 1136 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1137 |
function copyProfileLink() {
|
| 1138 |
navigator.clipboard.writeText(window.location.href).then(() => {
|
| 1139 |
alert('Ссылка скопирована!');
|
|
|
|
| 1143 |
if (localStorage.getItem('theme') === 'dark') document.body.classList.add('dark');
|
| 1144 |
const videos = document.querySelectorAll('.post-preview');
|
| 1145 |
videos.forEach(video => {
|
| 1146 |
+
video.addEventListener('loadedmetadata', () => {
|
| 1147 |
+
video.currentTime = Math.random() * video.duration;
|
| 1148 |
+
});
|
|
|
|
|
|
|
| 1149 |
});
|
| 1150 |
};
|
| 1151 |
</script>
|
|
|
|
| 1261 |
-webkit-background-clip: text;
|
| 1262 |
color: transparent;
|
| 1263 |
}
|
| 1264 |
+
.price {
|
| 1265 |
+
font-weight: 600;
|
| 1266 |
+
color: var(--primary);
|
| 1267 |
+
}
|
| 1268 |
</style>
|
| 1269 |
</head>
|
| 1270 |
<body>
|
|
|
|
| 1287 |
<button class="btn share-btn" onclick="copyProfileLink()">Поделиться</button>
|
| 1288 |
</div>
|
| 1289 |
</div>
|
| 1290 |
+
<h2>Видео</h2>
|
| 1291 |
<div class="post-grid">
|
| 1292 |
{% if user_posts %}
|
| 1293 |
{% for post in user_posts %}
|
| 1294 |
<div class="post-item">
|
| 1295 |
<a href="{{ url_for('post_page', post_id=post['id']) }}">
|
| 1296 |
+
<video class="post-preview" preload="metadata" muted>
|
| 1297 |
+
<source src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/videos/{{ post['filename'] }}" type="video/mp4">
|
| 1298 |
+
</video>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1299 |
<h3>{{ post['title'] }}</h3>
|
| 1300 |
</a>
|
| 1301 |
<p>{{ post['description'] }}</p>
|
| 1302 |
+
<p class="price">Цена: {{ post['price'] }} {{ post['currency'] }}</p>
|
| 1303 |
<p>{{ post['upload_date'] }}</p>
|
| 1304 |
</div>
|
| 1305 |
{% endfor %}
|
| 1306 |
{% else %}
|
| 1307 |
+
<p style="font-size: 1.2em;">Этот пользователь пока не загрузил ни одного видео.</p>
|
| 1308 |
{% endif %}
|
| 1309 |
</div>
|
| 1310 |
</div>
|
|
|
|
|
|
|
|
|
|
| 1311 |
<script>
|
| 1312 |
function toggleSidebar() {
|
| 1313 |
document.getElementById('sidebar').classList.toggle('active');
|
|
|
|
| 1316 |
document.body.classList.toggle('dark');
|
| 1317 |
localStorage.setItem('theme', document.body.classList.contains('dark') ? 'dark' : 'light');
|
| 1318 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1319 |
function copyProfileLink() {
|
| 1320 |
navigator.clipboard.writeText(window.location.href).then(() => {
|
| 1321 |
alert('Ссылка скопирована!');
|
|
|
|
| 1325 |
if (localStorage.getItem('theme') === 'dark') document.body.classList.add('dark');
|
| 1326 |
const videos = document.querySelectorAll('.post-preview');
|
| 1327 |
videos.forEach(video => {
|
| 1328 |
+
video.addEventListener('loadedmetadata', () => {
|
| 1329 |
+
video.currentTime = Math.random() * video.duration;
|
| 1330 |
+
});
|
|
|
|
|
|
|
| 1331 |
});
|
| 1332 |
};
|
| 1333 |
</script>
|
|
|
|
| 1347 |
username = session['username']
|
| 1348 |
user_data = data['users'].get(username, {})
|
| 1349 |
if user_data.get('type') != 'seller' or not user_data.get('verified'):
|
| 1350 |
+
flash('Только проверенные продавцы могут загружать видео!')
|
| 1351 |
return redirect(url_for('profile'))
|
| 1352 |
|
| 1353 |
if request.method == 'POST':
|
| 1354 |
title = request.form.get('title')
|
| 1355 |
description = request.form.get('description')
|
| 1356 |
+
price = request.form.get('price')
|
| 1357 |
+
currency = request.form.get('currency')
|
| 1358 |
file = request.files.get('file')
|
| 1359 |
uploader = session['username']
|
| 1360 |
|
| 1361 |
+
if not title or not price or not currency or not file:
|
| 1362 |
+
flash('Укажите название, цену, валюту и выберите видео!')
|
| 1363 |
+
return redirect(url_for('upload'))
|
| 1364 |
+
|
| 1365 |
+
if not file.filename.lower().endswith(('.mp4', '.mov', '.avi')):
|
| 1366 |
+
flash('Загружайте только видео файлы (mp4, mov, avi)!')
|
| 1367 |
+
return redirect(url_for('upload'))
|
| 1368 |
|
| 1369 |
filename = secure_filename(file.filename)
|
| 1370 |
temp_path = os.path.join('uploads', filename)
|
| 1371 |
os.makedirs('uploads', exist_ok=True)
|
| 1372 |
file.save(temp_path)
|
| 1373 |
|
|
|
|
| 1374 |
api = HfApi()
|
| 1375 |
api.upload_file(
|
| 1376 |
path_or_fileobj=temp_path,
|
| 1377 |
+
path_in_repo=f"videos/{filename}",
|
| 1378 |
repo_id=REPO_ID,
|
| 1379 |
repo_type="dataset",
|
| 1380 |
token=HF_TOKEN_WRITE,
|
| 1381 |
+
commit_message=f"Добавлено видео: {title} пользователем {uploader}"
|
| 1382 |
)
|
| 1383 |
|
| 1384 |
data = load_data()
|
|
|
|
| 1390 |
'title': title,
|
| 1391 |
'description': description,
|
| 1392 |
'filename': filename,
|
| 1393 |
+
'type': 'video',
|
| 1394 |
'uploader': uploader,
|
| 1395 |
'upload_date': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
|
| 1396 |
'views': 0,
|
| 1397 |
'likes': [],
|
| 1398 |
+
'comments': [],
|
| 1399 |
+
'price': price,
|
| 1400 |
+
'currency': currency
|
| 1401 |
})
|
| 1402 |
save_data(data)
|
| 1403 |
|
|
|
|
| 1413 |
<head>
|
| 1414 |
<meta charset="UTF-8">
|
| 1415 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 1416 |
+
<title>Загрузка видео</title>
|
| 1417 |
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600&display=swap" rel="stylesheet">
|
| 1418 |
<style>
|
| 1419 |
''' + BASE_STYLE + '''
|
|
|
|
| 1453 |
background: var(--primary);
|
| 1454 |
transition: width 0.4s ease;
|
| 1455 |
}
|
| 1456 |
+
.flash {
|
| 1457 |
+
color: var(--secondary);
|
| 1458 |
+
text-align: center;
|
| 1459 |
+
margin-bottom: 20px;
|
| 1460 |
+
font-size: 1.1em;
|
| 1461 |
+
font-weight: 500;
|
| 1462 |
+
}
|
| 1463 |
</style>
|
| 1464 |
</head>
|
| 1465 |
<body>
|
|
|
|
| 1467 |
''' + NAV_HTML + '''
|
| 1468 |
<button class="theme-toggle" onclick="toggleTheme()">🌙</button>
|
| 1469 |
<div class="container">
|
| 1470 |
+
<h1>Загрузить видео</h1>
|
| 1471 |
+
{% with messages = get_flashed_messages() %}
|
| 1472 |
+
{% if messages %}
|
| 1473 |
+
{% for message in messages %}
|
| 1474 |
+
<div class="flash">{{ message }}</div>
|
| 1475 |
+
{% endfor %}
|
| 1476 |
+
{% endif %}
|
| 1477 |
+
{% endwith %}
|
| 1478 |
<form id="upload-form" enctype="multipart/form-data">
|
| 1479 |
<input type="text" name="title" placeholder="Название" required>
|
| 1480 |
<textarea name="description" placeholder="Описание" rows="5"></textarea>
|
| 1481 |
+
<input type="number" name="price" placeholder="Цена" step="0.01" required>
|
| 1482 |
+
<select name="currency" required>
|
| 1483 |
+
<option value="USD">Доллар (USD)</option>
|
| 1484 |
+
<option value="RUB">Рубль (RUB)</option>
|
| 1485 |
+
<option value="KGS">Кыргызский сом (KGS)</option>
|
| 1486 |
+
<option value="KZT">Тенге (KZT)</option>
|
| 1487 |
+
<option value="UZS">Узбекский сум (UZS)</option>
|
| 1488 |
+
<option value="UAH">Украинская гривна (UAH)</option>
|
| 1489 |
+
<option value="PLN">Польский злотый (PLN)</option>
|
| 1490 |
+
</select>
|
| 1491 |
+
<input type="file" name="file" accept="video/*" required>
|
| 1492 |
<button type="submit" class="btn">Загрузить</button>
|
| 1493 |
</form>
|
| 1494 |
<div id="progress-container">
|
|
|
|
| 1677 |
.username-link:hover {
|
| 1678 |
text-decoration: underline;
|
| 1679 |
}
|
| 1680 |
+
.price {
|
| 1681 |
+
font-weight: 600;
|
| 1682 |
+
color: var(--primary);
|
| 1683 |
+
}
|
| 1684 |
</style>
|
| 1685 |
</head>
|
| 1686 |
<body>
|
|
|
|
| 1710 |
<p style="font-size: 1.2em;">Нет организаций на проверке.</p>
|
| 1711 |
{% endif %}
|
| 1712 |
</div>
|
| 1713 |
+
<h2>Все видео</h2>
|
| 1714 |
<div class="search-container">
|
| 1715 |
<form method="GET">
|
| 1716 |
<input type="text" name="search" class="search-input" placeholder="Поиск по названию или описанию" value="{{ search_query }}">
|
|
|
|
| 1722 |
{% for post in posts %}
|
| 1723 |
<div class="post-item">
|
| 1724 |
<a href="{{ url_for('post_page', post_id=post['id']) }}">
|
| 1725 |
+
<video class="post-preview" preload="metadata" muted>
|
| 1726 |
+
<source src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/videos/{{ post['filename'] }}" type="video/mp4">
|
| 1727 |
+
</video>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1728 |
<h3>{{ post['title'] }}</h3>
|
| 1729 |
</a>
|
| 1730 |
<p>{{ post['description'] }}</p>
|
| 1731 |
+
<p class="price">Цена: {{ post['price'] }} {{ post['currency'] }}</p>
|
| 1732 |
<p>Загрузил: <a href="{{ url_for('user_profile', username=post['uploader']) }}" class="username-link">{{ post['uploader'] }}</a> | {{ post['upload_date'] }}</p>
|
| 1733 |
<form method="POST">
|
| 1734 |
<input type="hidden" name="post_id" value="{{ post['id'] }}">
|
|
|
|
| 1737 |
</div>
|
| 1738 |
{% endfor %}
|
| 1739 |
{% else %}
|
| 1740 |
+
<p style="font-size: 1.2em;">Видео не найдены.</p>
|
| 1741 |
{% endif %}
|
| 1742 |
</div>
|
| 1743 |
</div>
|
|
|
|
| 1753 |
if (localStorage.getItem('theme') === 'dark') document.body.classList.add('dark');
|
| 1754 |
const videos = document.querySelectorAll('.post-preview');
|
| 1755 |
videos.forEach(video => {
|
| 1756 |
+
video.addEventListener('loadedmetadata', () => {
|
| 1757 |
+
video.currentTime = Math.random() * video.duration;
|
| 1758 |
+
});
|
|
|
|
|
|
|
| 1759 |
});
|
| 1760 |
};
|
| 1761 |
</script>
|