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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +177 -7
app.py CHANGED
@@ -282,7 +282,7 @@ def logout():
282
  @app.route('/')
283
  def feed():
284
  data = load_data()
285
- posts = data.get('posts', [])
286
  is_authenticated = 'username' in session
287
  username = session.get('username', None)
288
  html = '''
@@ -312,6 +312,8 @@ def feed():
312
  .modal { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.8); z-index: 2000; justify-content: center; align-items: center; }
313
  .modal img { max-width: 90%; max-height: 90%; object-fit: contain; transform: scale(1); transition: transform 0.2s ease; }
314
  .stats { font-size: 0.9em; color: #666; margin-top: 5px; }
 
 
315
  @media (max-width: 768px) {
316
  .sidebar { transform: translateX(-100%); width: 200px; }
317
  .sidebar.active { transform: translateX(0); }
@@ -341,7 +343,7 @@ def feed():
341
  {% endif %}
342
  <h2>{{ post['title'] }}</h2>
343
  <p>{{ post['description'] }}</p>
344
- <p>Загрузил: {{ post['uploader'] }} | {{ post['upload_date'] }}</p>
345
  <p class="stats">Просмотров: {{ post['views'] }} | Лайков: {{ post['likes']|length }}</p>
346
  </a>
347
  {% endfor %}
@@ -485,6 +487,8 @@ def post_page(post_id):
485
  .comment { border-top: 1px solid #e2e8f0; padding: 10px 0; }
486
  .modal { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.8); z-index: 2000; justify-content: center; align-items: center; }
487
  .modal img { max-width: 90%; max-height: 90%; object-fit: contain; transform: scale(1); transition: transform 0.2s ease; }
 
 
488
  @media (max-width: 768px) {
489
  .sidebar { transform: translateX(-100%); width: 200px; }
490
  .sidebar.active { transform: translateX(0); }
@@ -510,7 +514,7 @@ def post_page(post_id):
510
  <img src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/{{ post['type'] }}s/{{ post['filename'] }}" alt="{{ post['title'] }}" onclick="openModal(this.src)">
511
  {% endif %}
512
  <p>{{ post['description'] }}</p>
513
- <p>Загрузил: {{ post['uploader'] }} | {{ post['upload_date'] }}</p>
514
  <p>Просмотров: {{ post['views'] }} | Лайков: {{ post['likes']|length }}</p>
515
  {% if is_authenticated %}
516
  <form method="POST" style="display: inline;">
@@ -526,7 +530,7 @@ def post_page(post_id):
526
  <h3>Комментарии</h3>
527
  {% for comment in post.get('comments', []) %}
528
  <div class="comment">
529
- <p><strong>{{ comment['user'] }}</strong> ({{ comment['date'] }}): {{ comment['text'] }}</p>
530
  </div>
531
  {% endfor %}
532
  <a href="{{ url_for('feed') }}" class="btn">Назад к ленте</a>
@@ -603,7 +607,7 @@ def post_page(post_id):
603
  '''
604
  return render_template_string(html, post=post, repo_id=REPO_ID, is_authenticated=is_authenticated, username=username)
605
 
606
- # Страница профиля
607
  @app.route('/profile', methods=['GET', 'POST'])
608
  def profile():
609
  if 'username' not in session:
@@ -612,7 +616,7 @@ def profile():
612
 
613
  data = load_data()
614
  username = session['username']
615
- user_posts = [p for p in data['posts'] if p['uploader'] == username]
616
  is_authenticated = 'username' in session
617
 
618
  if request.method == 'POST':
@@ -711,7 +715,7 @@ def profile():
711
  }
712
 
713
  function openModal(src, event) {
714
- if (event) event.preventDefault();
715
  const modal = document.getElementById('imageModal');
716
  const modalImg = document.getElementById('modalImage');
717
  modal.style.display = 'flex';
@@ -783,6 +787,172 @@ def profile():
783
  '''
784
  return render_template_string(html, username=username, user_posts=user_posts, repo_id=REPO_ID, is_authenticated=is_authenticated)
785
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
786
  # Страница загрузки контента
787
  @app.route('/upload', methods=['GET', 'POST'])
788
  def upload():
 
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 = '''
 
312
  .modal { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.8); z-index: 2000; justify-content: center; align-items: center; }
313
  .modal img { max-width: 90%; max-height: 90%; object-fit: contain; transform: scale(1); transition: transform 0.2s ease; }
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); }
 
343
  {% endif %}
344
  <h2>{{ post['title'] }}</h2>
345
  <p>{{ post['description'] }}</p>
346
+ <p>Загрузил: <a href="{{ url_for('user_profile', username=post['uploader']) }}" class="username-link">{{ post['uploader'] }}</a> | {{ post['upload_date'] }}</p>
347
  <p class="stats">Просмотров: {{ post['views'] }} | Лайков: {{ post['likes']|length }}</p>
348
  </a>
349
  {% endfor %}
 
487
  .comment { border-top: 1px solid #e2e8f0; padding: 10px 0; }
488
  .modal { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.8); z-index: 2000; justify-content: center; align-items: center; }
489
  .modal img { max-width: 90%; max-height: 90%; object-fit: contain; transform: scale(1); transition: transform 0.2s ease; }
490
+ .username-link { color: #3b82f6; text-decoration: none; font-weight: 600; }
491
+ .username-link:hover { text-decoration: underline; }
492
  @media (max-width: 768px) {
493
  .sidebar { transform: translateX(-100%); width: 200px; }
494
  .sidebar.active { transform: translateX(0); }
 
514
  <img src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/{{ post['type'] }}s/{{ post['filename'] }}" alt="{{ post['title'] }}" onclick="openModal(this.src)">
515
  {% endif %}
516
  <p>{{ post['description'] }}</p>
517
+ <p>Загрузил: <a href="{{ url_for('user_profile', username=post['uploader']) }}" class="username-link">{{ post['uploader'] }}</a> | {{ post['upload_date'] }}</p>
518
  <p>Просмотров: {{ post['views'] }} | Лайков: {{ post['likes']|length }}</p>
519
  {% if is_authenticated %}
520
  <form method="POST" style="display: inline;">
 
530
  <h3>Комментарии</h3>
531
  {% for comment in post.get('comments', []) %}
532
  <div class="comment">
533
+ <p><strong><a href="{{ url_for('user_profile', username=comment['user']) }}" class="username-link">{{ comment['user'] }}</a></strong> ({{ comment['date'] }}): {{ comment['text'] }}</p>
534
  </div>
535
  {% endfor %}
536
  <a href="{{ url_for('feed') }}" class="btn">Назад к ленте</a>
 
607
  '''
608
  return render_template_string(html, post=post, repo_id=REPO_ID, is_authenticated=is_authenticated, username=username)
609
 
610
+ # Страница профиля текущего пользователя
611
  @app.route('/profile', methods=['GET', 'POST'])
612
  def profile():
613
  if 'username' not in session:
 
616
 
617
  data = load_data()
618
  username = session['username']
619
+ user_posts = sorted([p for p in data['posts'] if p['uploader'] == username], key=lambda x: datetime.strptime(x['upload_date'], '%Y-%m-%d %H:%M:%S'), reverse=True)
620
  is_authenticated = 'username' in session
621
 
622
  if request.method == 'POST':
 
715
  }
716
 
717
  function openModal(src, event) {
718
+ event.preventDefault();
719
  const modal = document.getElementById('imageModal');
720
  const modalImg = document.getElementById('modalImage');
721
  modal.style.display = 'flex';
 
787
  '''
788
  return render_template_string(html, username=username, user_posts=user_posts, repo_id=REPO_ID, is_authenticated=is_authenticated)
789
 
790
+ # Страница профиля другого пользователя
791
+ @app.route('/profile/<username>')
792
+ def user_profile(username):
793
+ data = load_data()
794
+ if username not in data['users']:
795
+ return "Пользователь не найден", 404
796
+
797
+ user_posts = sorted([p for p in data['posts'] if p['uploader'] == username], key=lambda x: datetime.strptime(x['upload_date'], '%Y-%m-%d %H:%M:%S'), reverse=True)
798
+ is_authenticated = 'username' in session
799
+ current_user = session.get('username', None)
800
+
801
+ html = '''
802
+ <!DOCTYPE html>
803
+ <html lang="ru">
804
+ <head>
805
+ <meta charset="UTF-8">
806
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
807
+ <title>Профиль - {{ username }}</title>
808
+ <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet">
809
+ <style>
810
+ body { font-family: 'Poppins', sans-serif; background: linear-gradient(135deg, #e0e7ff, #f3f4f6); margin: 0; padding: 0; min-height: 100vh; }
811
+ .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; }
812
+ .sidebar-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; }
813
+ .nav-brand { font-size: 1.5em; font-weight: 600; color: #3b82f6; }
814
+ .nav-links { display: flex; flex-direction: column; gap: 10px; }
815
+ .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; }
816
+ .nav-link:hover { background: rgba(59, 130, 246, 0.3); color: #2563eb; transform: translateX(5px); }
817
+ .logout-btn { background: rgba(239, 68, 68, 0.1); color: #ef4444; }
818
+ .logout-btn:hover { background: rgba(239, 68, 68, 0.3); color: #dc2626; }
819
+ .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); }
820
+ .container { max-width: 800px; margin: 20px auto 20px 270px; padding: 20px; transition: margin-left 0.3s ease; }
821
+ .post-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 20px; }
822
+ .post-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; }
823
+ .post-item:hover { transform: scale(1.02); }
824
+ .post-preview { width: 100%; border-radius: 8px; height: 200px; object-fit: cover; cursor: pointer; }
825
+ .btn { display: block; margin: 10px 0; padding: 12px 20px; background: rgba(59, 130, 246, 0.9); color: white; text-decoration: none; border-radius: 8px; border: none; cursor: pointer; transition: all 0.3s ease; }
826
+ .btn:hover { background: rgba(59, 130, 246, 1); transform: scale(1.05); }
827
+ .stats { font-size: 0.9em; color: #666; margin-top: 5px; }
828
+ .modal { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.8); z-index: 2000; justify-content: center; align-items: center; }
829
+ .modal img { max-width: 90%; max-height: 90%; object-fit: contain; transform: scale(1); transition: transform 0.2s ease; }
830
+ .username-link { color: #3b82f6; text-decoration: none; font-weight: 600; }
831
+ .username-link:hover { text-decoration: underline; }
832
+ @media (max-width: 768px) {
833
+ .sidebar { transform: translateX(-100%); width: 200px; }
834
+ .sidebar.active { transform: translateX(0); }
835
+ .menu-btn { display: block; }
836
+ .container { margin: 60px 10px 20px 10px; max-width: calc(100% - 20px); }
837
+ .post-grid { grid-template-columns: 1fr; gap: 15px; }
838
+ .post-item { padding: 10px; }
839
+ .post-preview { height: 150px; }
840
+ .btn { font-size: 14px; padding: 10px; }
841
+ h1, h2 { font-size: 1.5em; }
842
+ }
843
+ </style>
844
+ </head>
845
+ <body>
846
+ <button class="menu-btn" onclick="toggleSidebar()">☰</button>
847
+ ''' + NAV_HTML + '''
848
+ <div class="container">
849
+ <h1>Профиль: {{ username }}</h1>
850
+ <h2>Публикации</h2>
851
+ <div class="post-grid">
852
+ {% if user_posts %}
853
+ {% for post in user_posts %}
854
+ <div class="post-item">
855
+ <a href="{{ url_for('post_page', post_id=post['id']) }}">
856
+ {% if post['type'] == 'video' %}
857
+ <video class="post-preview" preload="metadata" muted>
858
+ <source src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/{{ post['type'] }}s/{{ post['filename'] }}" type="video/mp4">
859
+ </video>
860
+ {% else %}
861
+ <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)">
862
+ {% endif %}
863
+ <h3>{{ post['title'] }}</h3>
864
+ </a>
865
+ <p>{{ post['description'] }}</p>
866
+ <p>{{ post['upload_date'] }}</p>
867
+ <p class="stats">Просмотров: {{ post['views'] }} | Лайков: {{ post['likes']|length }}</p>
868
+ </div>
869
+ {% endfor %}
870
+ {% else %}
871
+ <p>Этот пользователь пока не загрузил ни одной публикации.</p>
872
+ {% endif %}
873
+ </div>
874
+ </div>
875
+ <div class="modal" id="imageModal" onclick="closeModal(event)">
876
+ <img id="modalImage" src="">
877
+ </div>
878
+ <script>
879
+ function toggleSidebar() {
880
+ document.getElementById('sidebar').classList.toggle('active');
881
+ }
882
+
883
+ function openModal(src, event) {
884
+ event.preventDefault();
885
+ const modal = document.getElementById('imageModal');
886
+ const modalImg = document.getElementById('modalImage');
887
+ modal.style.display = 'flex';
888
+ modalImg.src = src;
889
+ modalImg.style.transform = 'scale(1)';
890
+ }
891
+
892
+ function closeModal(event) {
893
+ if (event.target.tagName !== 'IMG') {
894
+ const modal = document.getElementById('imageModal');
895
+ modal.style.display = 'none';
896
+ }
897
+ }
898
+
899
+ document.addEventListener('DOMContentLoaded', function() {
900
+ const videos = document.querySelectorAll('.post-preview');
901
+ videos.forEach(video => {
902
+ if (video.tagName === 'VIDEO') {
903
+ video.addEventListener('loadedmetadata', function() {
904
+ const duration = video.duration;
905
+ const randomTime = Math.random() * duration;
906
+ video.currentTime = randomTime;
907
+ });
908
+ }
909
+ });
910
+
911
+ const modalImg = document.getElementById('modalImage');
912
+ let scale = 1;
913
+ let startDistance = 0;
914
+ let lastTap = 0;
915
+
916
+ modalImg.addEventListener('dblclick', function() {
917
+ scale = scale === 1 ? 2 : 1;
918
+ modalImg.style.transform = `scale(${scale})`;
919
+ });
920
+
921
+ modalImg.addEventListener('touchstart', function(e) {
922
+ if (e.touches.length === 2) {
923
+ startDistance = getDistance(e.touches[0], e.touches[1]);
924
+ } else if (e.touches.length === 1) {
925
+ const now = new Date().getTime();
926
+ if (now - lastTap < 300) {
927
+ scale = scale === 1 ? 2 : 1;
928
+ modalImg.style.transform = `scale(${scale})`;
929
+ }
930
+ lastTap = now;
931
+ }
932
+ });
933
+
934
+ modalImg.addEventListener('touchmove', function(e) {
935
+ if (e.touches.length === 2) {
936
+ e.preventDefault();
937
+ const currentDistance = getDistance(e.touches[0], e.touches[1]);
938
+ scale = Math.max(1, Math.min(3, scale * (currentDistance / startDistance)));
939
+ modalImg.style.transform = `scale(${scale})`;
940
+ startDistance = currentDistance;
941
+ }
942
+ });
943
+
944
+ function getDistance(touch1, touch2) {
945
+ const dx = touch1.pageX - touch2.pageX;
946
+ const dy = touch1.pageY - touch2.pageY;
947
+ return Math.sqrt(dx * dx + dy * dy);
948
+ }
949
+ });
950
+ </script>
951
+ </body>
952
+ </html>
953
+ '''
954
+ return render_template_string(html, username=username, user_posts=user_posts, repo_id=REPO_ID, is_authenticated=is_authenticated, current_user=current_user)
955
+
956
  # Страница загрузки контента
957
  @app.route('/upload', methods=['GET', 'POST'])
958
  def upload():