i have a flask app this is my main.py:
import os
import json
from passlib.context import CryptContext
from PIL import Image
from flask import Flask, render_template, url_for, redirect, request, send_from_directory, flash
from flask_login import LoginManager, login_user, current_user, logout_user
from flask_restful import Api
from data import db_session
from data.videos import Video
from data.users import User
from sqlalchemy.orm import joinedload
from data.login_form import LoginForm
from data.register_form import RegisterForm
from data.video_form import VideoForm
from data.users_resource import UsersResource, UserListResource
from data.videos_resource import VideosResource, VideoListResource
from data.likes_resource import LikeResource, NotLikeResource
from data.subscriptions_resource import FollowResource, NotFollowResource
from werkzeug.utils import secure_filename
from data.avatar_form import AvatarForm
from data.comments import Comment
from data.comment_form import CommentForm
app = Flask(__name__)
app.config['SECRET_KEY'] = 'yandexlyceum_secret_key'

api = Api(app)

login_manager = LoginManager()
login_manager.init_app(app)

pwd_context = CryptContext(
    schemes=["pbkdf2_sha256"],
    default="pbkdf2_sha256",
    pbkdf2_sha256__default_rounds=30000
)


# Set the folder to store avatars
AVATAR_UPLOAD_FOLDER = os.path.join(app.root_path, 'static', 'avatars')
# Allowed extensions
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}

app.config['AVATAR_UPLOAD_FOLDER'] = AVATAR_UPLOAD_FOLDER
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024  # 2MB max upload sizes

@app.route('/favicon.ico')
def favicon():
    """Возвращает кастомную иконку страницы в браузере"""
    return send_from_directory(os.path.join(app.root_path, 'static/img'),
                               'vhs.ico', mimetype='image/vnd.microsoft.icon')


def load_user(user_id):
    """Loads the user by ID."""
    return db_sess.query(User).get(user_id)

@app.route('/upload_avatar', methods=['GET', 'POST'])
def upload_avatar():
    """Allows authenticated users to upload their avatar."""
    form = AvatarForm()
    if form.validate_on_submit():
        avatar = form.avatar.data
        # Secure the filename
        filename = secure_filename(avatar.filename)
        # Create a unique filename using user ID
        file_ext = os.path.splitext(filename)[1].lower()
        avatar_filename = f"user_{current_user.id}{file_ext}"
        avatar_path = os.path.join(app.config['AVATAR_UPLOAD_FOLDER'], avatar_filename)

        # Save the avatar temporarily
        avatar.save(avatar_path)

        # Validate and process the image
        try:
            img = Image.open(avatar_path)
            img = img.convert('RGB')  # Ensure image is in RGB
            img.thumbnail((300, 300))  # Resize to 300x300 pixels
            img.save(avatar_path, optimize=True, quality=85)  # Optimize and save
        except Exception as e:
            os.remove(avatar_path)
            flash('Неправильный формат файла!', 'danger')
            return render_template('upload_avatar.html', form=form)

        # Update user's avatar in the database
        current_user.avatar = avatar_filename
        db_sess.commit()

        flash('Аватар загружен успешно!', 'success')
        return redirect(url_for('user', user_id=current_user.id))
    else:
        if form.errors:
            # Aggregate form errors
            error_messages = '; '.join([' '.join(err) for err in form.errors.values()])
            flash(error_messages, 'danger')
    return render_template('upload_avatar.html', form=form)



@app.errorhandler(403)
def forbidden(e):
    """Возвращает кастомную страницу ошибки 403"""
    params = {
        'title': 'Доступ запрещен',
        'message': 'Похоже, у вас нет доступа к этой странице ¯\\_(ツ)_/¯',
        'authenticated': current_user.is_authenticated,
        'current_user': current_user
    }
    return render_template('error.html', **params), 403

def to_int(value):
    try:
        return int(value)
    except ValueError:
        return 0  # or handle as needed

app.jinja_env.filters['to_int'] = to_int

@app.errorhandler(404)
def page_not_found(e):
    """Возвращает кастомную страницу ошибки 404"""
    params = {
        'title': 'Страница не найдена',
        'message': 'Похоже, мы не можем найти нужную вам страницу ¯\\_(ツ)_/¯',
        'authenticated': current_user.is_authenticated,
        'current_user': current_user
    }
    return render_template('error.html', **params), 404


@app.errorhandler(405)
def method_not_allowed(e):
    """Возвращает кастомную страницу ошибки 405"""
    params = {
        'title': 'Метод не разрешен',
        'message': 'Похоже, этот метод не разрешен ¯\\_(ツ)_/¯',
        'authenticated': current_user.is_authenticated,
        'current_user': current_user
    }
    return render_template('error.html', **params), 405


@app.errorhandler(500)
def internal_server_error(e):
    """Возвращает кастомную страницу ошибки 500"""
    params = {
        'title': 'Ошибка сервера',
        'message': 'Похоже, на сервере произошла непредвиденная ошибка ¯\\_(ツ)_/¯',
        'authenticated': current_user.is_authenticated,
        'current_user': current_user
    }
    return render_template('error.html', **params), 500


@app.route('/')
@app.route('/index')
def index():
    """Возвращает домашнюю страницу"""
    all_videos = db_sess.query(Video).all()
    if len(all_videos) > 10:
        last_videos = all_videos[len(all_videos) - 10:][::-1]
    else:
        last_videos = all_videos[::-1]
    best_videos = sorted(all_videos, key=lambda x: -x.likes)[:3]
    underrated_videos = list(filter(lambda x: x.likes == 0, all_videos))
    if len(underrated_videos) > 9:
        underrated_videos = underrated_videos[len(underrated_videos) - 9:][::-1]
    else:
        underrated_videos = underrated_videos[::-1]

    params = {
        'title': 'Video Hosting Service',
        'last_videos': last_videos,
        'best_videos': best_videos,
        'underrated_videos': underrated_videos,
        'user': user,
        'db_sess': db_sess,
        'User': User,
        'Video': Video,
        'authenticated': current_user.is_authenticated,
        'all_videos': all_videos,
        'current_user': current_user
    }
    return render_template('index.html', **params)


@login_manager.user_loader
def load_user(user_id):
    """Возвращает пользователя"""
    return db_sess.query(User).get(user_id)


@app.route('/login', methods=['GET', 'POST'])
def login():
    """Возвращает страницу авторизации и авторизует пользователя"""
    if current_user.is_authenticated:
        return forbidden('')
    form = LoginForm()
    params = {
        'title': 'Авторизация',
        'authenticated': current_user.is_authenticated,
        'current_user': current_user
    }
    if form.validate_on_submit():
        user = db_sess.query(User).filter(User.login == form.login.data).first()
        if user and pwd_context.verify(form.password.data, user.password):
            login_user(user, remember=form.remember_me.data)
            return redirect('/')
        return render_template('login.html',
                               message='Неправильный логин или пароль',
                               form=form, **params)
    return render_template('login.html', form=form, **params)


@app.route('/register', methods=['GET', 'POST'])
def register():
    """Возвращает страницу регистрации и регистрирует пользователя"""
    if current_user.is_authenticated:
        return forbidden('')
    form = RegisterForm()
    params = {
        'title': 'Регистрация',
        'authenticated': current_user.is_authenticated,
        'current_user': current_user
    }
    if form.validate_on_submit():
        user = db_sess.query(User).filter(User.login == form.login.data).all()
        if user:
            return render_template('register.html',
                                   message='Пользователь с таким логином уже существует',
                                   form=form, **params)
        if form.password.data != form.repeat_password.data:
            return render_template('register.html',
                                   message='Пароли не совпадают',
                                   form=form, **params)
        user = User()
        user.login = form.login.data
        user.password = pwd_context.hash(form.password.data)
        user.name = form.name.data
        user.surname = form.surname.data
        db_sess.add(user)
        db_sess.commit()
        login_user(user, remember=form.remember_me.data)
        return redirect('/')
    return render_template('register.html', form=form, **params)


@app.route('/logout')
def logout():
    """
    Производит выход пользователя из системы, возвращает домашнюю страницу.
    Если пользователь не авторизован, возвращает страницу ошибки 403
    """
    if current_user.is_authenticated:
        logout_user()
        return redirect('/')
    else:
        return forbidden('')
@app.route('/api/pin_comment/<int:comment_id>', methods=['POST'])
def pin_comment(comment_id):
    comment = db_sess.query(Comment).get(comment_id)
    if not comment:
        return {'error': 'Comment not found'}, 404
    video = db_sess.query(Video).get(comment.video_id)

    # Сбрасываем все закрепленные комментарии для данного видео
    db_sess.query(Comment).filter(Comment.video_id == video.id).update({'pinned': False})
    # Закрепляем выбранный комментарий
    comment.pinned = True
    db_sess.commit()
    return {'success': True}
@app.route('/delete_comment/<int:comment_id>', methods=['POST'])
def delete_comment(comment_id):
    comment = db_sess.query(Comment).get(comment_id)
    if not comment:
        flash('Комментарий не найден.', 'danger')
        return redirect(request.referrer)
    if not current_user.is_authenticated or current_user.id != comment.user_id:
        flash('Вы не можете удалить этот комментарий.', 'danger')
        return redirect(request.referrer)
    db_sess.delete(comment)
    db_sess.commit()
    flash('Комментарий удален.', 'success')
    return redirect(request.referrer)
from flask import abort

@app.route('/video/<int:video_id>', methods=['GET', 'POST'])
def video(video_id):
    current_video = db_sess.query(Video).get(video_id)
    if current_video is None:
        return page_not_found('')

    # Проверяем, разрешены ли комментарии для этого видео
    comments_enabled = current_video.comments_enabled

    # Получаем автора видео
    author = db_sess.query(User).get(current_video.author)

    # Проверяем, поставил ли текущий пользователь лайк и подписан ли
    like = False
    subscription = False
    if current_user.is_authenticated:
        likes = json.loads(current_user.likes)
        subscriptions = json.loads(current_user.subscriptions)
        if video_id in likes:
            like = True
        if current_video.author in subscriptions:
            subscription = True

    # Обрабатываем форму комментария
    # Обрабатываем форму комментария только если комментарии включены
    form = CommentForm()
    if comments_enabled and form.validate_on_submit():
        if current_user.is_authenticated and not current_user.is_blocked:
            # Добавление комментария
            comment = Comment(
                content=form.content.data,
                user_id=current_user.id,
                video_id=video_id,
                parent_id=form.parent_id.data or None
            )
            db_sess.add(comment)
            db_sess.commit()
            flash('Комментарий добавлен!', 'success')
            return redirect(url_for('video', video_id=video_id))
        else:
            flash('Вы не можете оставить комментарий.', 'danger')
            return redirect

    # Получаем комментарии к видео


    comments = db_sess.query(Comment).filter(Comment.video_id == video_id).options(
        joinedload(Comment.user),
        joinedload(Comment.parent).joinedload(Comment.user),
        joinedload(Comment.replies).joinedload(Comment.user)
    ).order_by(Comment.datetime.desc()).all()  # Изменено на desc() для сортировки в обратном порядке

    # Создаем словарь комментариев по id для удобства доступа
    comments_by_id = {comment.id: comment for comment in comments}

    # Строим дерево комментариев
    root_comments = []
    for comment in comments:
        if comment.parent_id is None:
            root_comments.append(comment)
        else:
            parent = comments_by_id.get(comment.parent_id)
            if parent:
                if not hasattr(parent, 'replies_sorted'):
                    parent.replies_sorted = []
                parent.replies_sorted.append(comment)

    params = {
        'title': f"{current_video.title} - {author.name} {author.surname}",
        'current_video': current_video,
        'video_src': url_for("static", filename=f'vid/{video_id}.mp4'),
        'author': author,
        'like': like,
        'subscription': subscription,
        'db_sess': db_sess,
        'comments': root_comments,
        'User': User,
        'authenticated': current_user.is_authenticated,
        'current_user': current_user,
        'avatar_url': url_for('static', filename=f'avatars/{author.avatar}'),
        'comments': comments,
        'form': form
    }
    return render_template('video.html', **params)


@app.route('/add_video', methods=['GET', 'POST'])
def add_video():
    if not current_user.is_authenticated:
        return forbidden('')
    form = VideoForm()
    params = {
        'title': 'Добавление видео',
        'authenticated': current_user.is_authenticated,
        'current_user': current_user
    }
    # Добавляем проверку на блокировку
    if current_user.is_blocked:
        flash('Ваш аккаунт заблокирован и вы не можете загружать видео.', 'danger')
        return render_template('add_video.html', form=form, **params)

    if form.validate_on_submit():
        video_file = request.files['video']
        if not video_file.filename.lower().endswith('.mp4'):
            return render_template('add_video.html',
                                   message='Данный формат видео не поддерживается. '
                                           'Пожалуйста, загрузите видео в формате mp4.',
                                   form=form, **params)
        preview_file = request.files['preview']
        if not preview_file.filename.lower().endswith('.jpg'):
            return render_template('add_video.html',
                                   message='Данный формат обложки не поддерживается. '
                                           'Пожалуйста, загрузите изображение в формате jpg.',
                                   form=form, **params)
        video = Video()
        video.title = form.title.data
        video.description = '<br>'.join(form.description.data.split('\n'))
        video.author = current_user.id
        video.comments_enabled = form.comments_enabled.data  # Сохраняем значение флажка
        db_sess.add(video)
        db_sess.commit()
        video_file.save(os.path.join('static/vid', f'{video.id}.mp4'))
        preview_file.save(os.path.join('static/pre', f'{video.id}.jpg'))
        with Image.open(f'static/pre/{video.id}.jpg') as preview_file:
            width, height = preview_file.size
            if width >= height:
                new_width = height * 16 // 9
                delta = (width - new_width) // 2
                preview_file = preview_file.crop((delta, 0, new_width + delta, height))
            else:
                new_height = width * 9 // 16
                delta = (height - new_height) // 2
                preview_file = preview_file.crop((0, delta, width, new_height + delta))
            preview_file.save(f'static/pre/{video.id}.jpg')
        return redirect('/')
    return render_template('add_video.html', form=form, **params)


@app.route('/edit_video/<int:video_id>', methods=['GET', 'POST'])
def edit_video(video_id):
    """
    Возвращает страницу редактирования видео
    если пользователь авторизован и является автором,
    иначе доступ запрщен
    """
    form = VideoForm()
    video = db_sess.query(Video).get(video_id)
    if not current_user.is_authenticated:
        return forbidden('')
    if not current_user.id != video.author:
        return forbidden('')

    params = {
        'title': 'Редактирование видео',
        'video': video,
        'description': '\n'.join(video.description.split('<br>')),
        'authenticated': current_user.is_authenticated,
        'current_user': current_user
    }
    if form.validate_on_submit():
        video_file = request.files['video']
        if not video_file.filename.lower().endswith('.mp4'):
            return render_template('edit_video.html',
                                   message='Данный формат видео не поддерживается',
                                   form=form, **params)
        preview_file = request.files['preview']
        if not preview_file.filename.lower().endswith('.jpg'):
            return render_template('edit_video.html',
                                   message='Данный формат обложки не поддерживается',
                                   form=form, **params)
        video.title = form.title.data
        video.description = '<br>'.join(form.description.data.split('\n'))
        db_sess.commit()
        video_file.save(os.path.join('static/vid', f'{video.id}.mp4'))
        preview_file.save(os.path.join('static/pre', f'{video.id}.jpg'))
        with Image.open(f'static/pre/{video.id}.jpg') as preview_file:
            width, height = preview_file.size
            if width >= height:
                new_width = height * 16 // 9
                delta = (width - new_width) // 2
                preview_file = preview_file.crop((delta, 0, new_width + delta, height))
            else:
                new_height = width * 9 // 16
                delta = (height - new_height) // 2
                preview_file = preview_file.crop((0, delta, width, new_height + delta))
            preview_file.save(f'static/pre/{video.id}.jpg')
        return redirect('/')
    return render_template('edit_video.html', form=form, **params)


@app.route('/delete_video/<int:video_id>')
def delete_video(video_id):
    """
    Удаляет видео если пользователь авторизован и является автором,
    иначе доступ запрещен
    """
    video = db_sess.query(Video).get(video_id)
    if not int(current_user.id) == int(video.author):
        print(f"Current user ID: {current_user.id}, Video author ID: {video.author}")  # Debugging line
        return redirect('/')
    db_sess.delete(video)
    db_sess.commit()
    os.remove(os.path.join('static/vid', f'{video.id}.mp4'))
    os.remove(os.path.join('static/pre', f'{video.id}.jpg'))
    return redirect(f'/user/{current_user.id}')


@app.route('/user/<int:user_id>')
def user(user_id):
    """Возвращает страницу выбранного пользователя с его видео"""
    user = db_sess.query(User).get(user_id)
    if user is None:
        return page_not_found('')

    # Получаем все видео пользователя
    videos = db_sess.query(Video).filter(Video.author == user_id).all()[::-1]

    # Вычисляем количество видео
    video_count = len(videos)
    # Альтернативно, для оптимизации можно использовать:
    # video_count = db_sess.query(Video).filter(Video.author == user_id).count()

    subscription = False
    if current_user.is_authenticated:
        subscriptions = json.loads(current_user.subscriptions)
        if user_id in subscriptions:
            subscription = True

    # Пагинация видео (разбивка на группы по 3 видео)
    paginated_videos = [videos[i * 3:i * 3 + 3] for i in range(len(videos) // 3)] + [videos[(len(videos) // 3) * 3:]]

    # Добавляем все необходимые параметры, включая video_count
    params = {
        'title': f'{user.name} {user.surname}',
        'user': user,
        'videos': paginated_videos,
        'subscription': subscription,
        'empty': True if len(videos) == 0 else False,
        'authenticated': current_user.is_authenticated,
        'current_user': current_user,
        'video_count': video_count  # Передаём количество видео
    }
    return render_template('user.html', **params)
def decline_subscription(number):
    """
    Возвращает правильную форму слова "подписчик" в зависимости от числа.
    Например:
        1 -> подписчик
        2 -> подписчика
        5 -> подписчиков
    """
    number = abs(number)  # Убираем знак, если число отрицательное
    last_two = number % 100
    last = number % 10

    if 11 <= last_two <= 14:
        return "подписчиков"
    if last == 1:
        return "подписчик"
    if 2 <= last <= 4:
        return "подписчика"
    return "подписчиков"

# Регистрация фильтра в Jinja2
app.jinja_env.filters['decline_subscription'] = decline_subscription
from data.users import User
from sqlalchemy import update

@app.route('/admin/users', methods=['GET', 'POST'])
def admin_users():
    """Административная страница для управления флажками, блокировками и статусом админа пользователей"""
    if not current_user.is_authenticated or not current_user.is_admin:
        return forbidden('')  # Только администратор имеет доступ

    users = db_sess.query(User).all()

    if request.method == 'POST':
        # Обработка изменений флажков, блокировок и статуса админа
        for user in users:
            if user.id == 1:
                continue  # Не изменять статус администратора

            # Обработка флажков is_checked
            is_checked = request.form.get(f'checked_{user.id}', 'off') == 'on'
            if user.is_checked != is_checked:
                user.is_checked = is_checked
                db_sess.add(user)

            # Обработка блокировок is_blocked
            is_blocked = request.form.get(f'blocked_{user.id}', 'off') == 'on'
            if user.is_blocked != is_blocked:
                user.is_blocked = is_blocked
                db_sess.add(user)

            # Обработка статуса администратора is_admin
            is_admin = request.form.get(f'is_admin_{user.id}', 'off') == 'on'
            if user.is_admin != is_admin:
                user.is_admin = is_admin
                db_sess.add(user)
        db_sess.commit()
        flash('Изменения успешно сохранены.', 'success')
        return redirect(url_for('admin_users'))

    params = {
        'title': 'Администрирование пользователей',
        'users': users,
        'authenticated': current_user.is_authenticated,
        'current_user': current_user
    }
    return render_template('admin_users.html', **params)
@app.route('/feed')
def feed():
    """
    Возвращает страницу с лентой видео от людей,
    на которых подписан пользователь.
    Если пользователь не авторизован, доступ запрещен
    """
    if not current_user.is_authenticated:
        return forbidden('')
    subscriptions = json.loads(current_user.subscriptions)
    videos = []
    for i in subscriptions:
        videos += db_sess.query(Video).filter(Video.author == i).all()[::-1][:12]
    new_videos = sorted(videos, key=lambda x: x.datetime)[::-1]
    new_videos = [
        {
            'video': i,
            'author': db_sess.query(User).get(i.author)
        }
        for i in new_videos
    ]
    params = {
        'title': f'Лента',
        'new_videos': [new_videos[i * 3:i * 3 + 3] for i in range(len(new_videos) // 3)] +
                      [new_videos[(len(new_videos) // 3) * 3:]],
        'empty': True if len(new_videos) == 0 else False,
        'subscripted': True if len(subscriptions) != 0 else False,
        'authenticated': current_user.is_authenticated,
        'current_user': current_user
    }
    return render_template('feed.html', **params)


@app.route('/favorite')
def favorite():
    """
    Возвращает страницу с любимыми видео пользователя.
    Если пользователь не авторизован, доступ запрещен
    """
    if not current_user.is_authenticated:
        return forbidden('')
    likes = json.loads(current_user.likes)[::-1]
    liked_videos = [
    {
        'video': video,
        'author': db_sess.query(User).get(video.author) if video.author else None
    }
    for i in likes
    if (video := db_sess.query(Video).get(i)) is not None
]
    params = {
        'title': f'Любимое',
        'liked_videos': [liked_videos[i * 3:i * 3 + 3] for i in range(len(liked_videos) // 3)] +
                        [liked_videos[(len(liked_videos) // 3) * 3:]],
        'empty': True if len(liked_videos) == 0 else False,
        'authenticated': current_user.is_authenticated,
        'current_user': current_user
    }
    return render_template('favorite.html', **params)


@app.route('/people')
def people():
    """
    Возвращает страницу с пользователями, на которых подписан пользователь.
    Если пользователь не авторизован, доступ запрещен
    """
    if not current_user.is_authenticated:
        return forbidden('')
    subscriptions = json.loads(current_user.subscriptions)
    subscripted_users = [
        {
            'user': db_sess.query(User).get(i)
        }
        for i in subscriptions
    ]
    subscripted_users.sort(key=lambda x: x['user'].name + x['user'].surname + x['user'].login)
    params = {
        'title': f'Люди',
        'subscripted_users': subscripted_users,
        'empty': True if len(subscripted_users) == 0 else False,
        'authenticated': current_user.is_authenticated,
        'current_user': current_user
    }
    return render_template('people.html', **params)
from data.edit_profile_form import EditProfileForm  # Импортируем форму

@app.route('/edit_profile', methods=['GET', 'POST'])
def edit_profile():
    """Страница редактирования профиля пользователя"""
    if not current_user.is_authenticated:
        return forbidden('')

    form = EditProfileForm(obj=current_user)  # Заполняем форму текущими данными пользователя
    params = {
        'title': 'Редактирование профиля',
        'authenticated': current_user.is_authenticated,
        'current_user': current_user
    }

    if form.validate_on_submit():
        # Проверяем, если пользователь изменяет логин, убедимся, что он уникален
        if form.login.data and form.login.data != current_user.login:
            existing_user = db_sess.query(User).filter(User.login == form.login.data).first()
            if existing_user:
                flash('Пользователь с таким логином уже существует.', 'danger')
                return render_template('edit_profile.html', form=form, **params)
            else:
                current_user.login = form.login.data

        # Обновляем имя и фамилию, если они были изменены
        if form.name.data:
            current_user.name = form.name.data
        if form.surname.data:
            current_user.surname = form.surname.data

        # Обновляем пароль, если введён новый
        if form.password.data:
            current_user.password = pwd_context.hash(form.password.data)

        db_sess.commit()
        flash('Профиль обновлён успешно!', 'success')
        return redirect(url_for('user', user_id=current_user.id))
    else:
        if form.errors:
            # Объединяем все ошибки формы в одно сообщение
            error_messages = '; '.join([' '.join(errors) for errors in form.errors.values()])
            flash(error_messages, 'danger')

    return render_template('edit_profile.html', form=form, **params)
@app.route('/api/comment_like/<int:comment_id>', methods=['POST'])
def comment_like(comment_id):
    if not current_user.is_authenticated:
        return {'error': 'Unauthorized'}, 401
    comment = db_sess.query(Comment).get(comment_id)
    if not comment:
        return {'error': 'Comment not found'}, 404
    likes = json.loads(current_user.comment_likes)
    if comment_id in likes:
        return {'error': 'Already liked'}, 400
    likes.append(comment_id)
    current_user.comment_likes = json.dumps(likes)
    comment.likes += 1
    db_sess.commit()
    return {'success': True, 'likes': comment.likes}

@app.route('/api/comment_unlike/<int:comment_id>', methods=['POST'])
def comment_unlike(comment_id):
    if not current_user.is_authenticated:
        return {'error': 'Unauthorized'}, 401
    comment = db_sess.query(Comment).get(comment_id)
    if not comment:
        return {'error': 'Comment not found'}, 404
    likes = json.loads(current_user.comment_likes)
    if comment_id not in likes:
        return {'error': 'Not liked'}, 400
    likes.remove(comment_id)
    current_user.comment_likes = json.dumps(likes)
    comment.likes -= 1
    db_sess.commit()
    return {'success': True, 'likes': comment.likes}
@app.route('/about')
def about():
    params = {
        'title': f'Про сайт'

    }
    return render_template('about.html', **params)
from flask import request, render_template
from sqlalchemy import or_

from flask import request, render_template
from sqlalchemy import or_

@app.route('/search')
def search():
    """Возвращает страницу с результатами поиска видео"""
    query = request.args.get('search', '').strip()

    if query:
        # Use ilike for case-insensitive search. Ensure database supports case-insensitive collation.
        videos = db_sess.query(Video).filter(Video.title.ilike(f'%{query}%')).all()
    else:
        videos = []

    params = {
        'title': f'Поиск: {query}',
        'query': query,
        'videos': videos,
        'empty': len(videos) == 0,
        'db_sess': db_sess,
        'User': User,
        'authenticated': current_user.is_authenticated,
        'current_user': current_user
    }
    return render_template('search.html', **params)

from data.db_session import SqlAlchemyBase

db_session.global_init("db/hosting.sql")
from data import __all_models
db_sess = db_session.create_session()

db_sess.rollback

SqlAlchemyBase.metadata.create_all(bind=db_sess.bind)
api.add_resource(UsersResource, '/api/users/<int:user_id>')
api.add_resource(UserListResource, '/api/users')
api.add_resource(VideosResource, '/api/videos/<int:video_id>')
api.add_resource(VideoListResource, '/api/videos')
api.add_resource(LikeResource, '/api/like/<int:video_id>')
api.add_resource(NotLikeResource, '/api/not_like/<int:video_id>')
api.add_resource(FollowResource, '/api/follow/<int:user_id>')
api.add_resource(NotFollowResource, '/api/not_follow/<int:user_id>')


if __name__ == '__main__':
    from waitress import serve
    app.run(debug=True, port=8080, host='0.0.0.0')
and this is my video.html:
{% extends "base.html" %}

{% block content %}
    <div class="row">
        <div class="col-9">
            <div class="row">
                <div class="col">
                <div class="video-container paused" data-volume-level="high">
    <img class="thumbnail-img">
    <div class="video-controls-container">
      <div class="timeline-container">
        <div class="timeline">
          <img class="preview-img">
          <div class="thumb-indicator"></div>
        </div>
      </div>
      <div class="controls">
        <button class="play-pause-btn">
          <svg class="play-icon" viewBox="0 0 24 24">
            <path fill="currentColor" d="M8,5.14V19.14L19,12.14L8,5.14Z" />
          </svg>
          <svg class="pause-icon" viewBox="0 0 24 24">
            <path fill="currentColor" d="M14,19H18V5H14M6,19H10V5H6V19Z" />
          </svg>
        </button>
        <div class="volume-container">
          <button class="mute-btn">
            <svg class="volume-high-icon" viewBox="0 0 24 24">
              <path fill="currentColor" d="M14,3.23V5.29C16.89,6.15 19,8.83 19,12C19,15.17 16.89,17.84 14,18.7V20.77C18,19.86 21,16.28 21,12C21,7.72 18,4.14 14,3.23M16.5,12C16.5,10.23 15.5,8.71 14,7.97V16C15.5,15.29 16.5,13.76 16.5,12M3,9V15H7L12,20V4L7,9H3Z" />
            </svg>
            <svg class="volume-low-icon" viewBox="0 0 24 24">
              <path fill="currentColor" d="M5,9V15H9L14,20V4L9,9M18.5,12C18.5,10.23 17.5,8.71 16,7.97V16C17.5,15.29 18.5,13.76 18.5,12Z" />
            </svg>
            <svg class="volume-muted-icon" viewBox="0 0 24 24">
              <path fill="currentColor" d="M12,4L9.91,6.09L12,8.18M4.27,3L3,4.27L7.73,9H3V15H7L12,20V13.27L16.25,17.53C15.58,18.04 14.83,18.46 14,18.7V20.77C15.38,20.45 16.63,19.82 17.68,18.96L19.73,21L21,19.73L12,10.73M19,12C19,12.94 18.8,13.82 18.46,14.64L19.97,16.15C20.62,14.91 21,13.5 21,12C21,7.72 18,4.14 14,3.23V5.29C16.89,6.15 19,8.83 19,12M16.5,12C16.5,10.23 15.5,8.71 14,7.97V10.18L16.45,12.63C16.5,12.43 16.5,12.21 16.5,12Z" />
            </svg>
          </button>
          <input class="volume-slider" type="range" min="0" max="1" step="any" value="1">
        </div>
        <div class="duration-container">
          <div class="current-time">0:00</div>
          /
          <div class="total-time"></div>
        </div>
        <button class="captions-btn">
          <svg viewBox="0 0 24 24">
            <path fill="currentColor" d="M18,11H16.5V10.5H14.5V13.5H16.5V13H18V14A1,1 0 0,1 17,15H14A1,1 0 0,1 13,14V10A1,1 0 0,1 14,9H17A1,1 0 0,1 18,10M11,11H9.5V10.5H7.5V13.5H9.5V13H11V14A1,1 0 0,1 10,15H7A1,1 0 0,1 6,14V10A1,1 0 0,1 7,9H10A1,1 0 0,1 11,10M19,4H5C3.89,4 3,4.89 3,6V18A2,2 0 0,0 5,20H19A2,2 0 0,0 21,18V6C21,4.89 20.1,4 19,4Z" />
          </svg>
        </button>
        <button class="speed-btn wide-btn">
          1x
        </button>
        <button class="mini-player-btn">
          <svg viewBox="0 0 24 24">
            <path fill="currentColor" d="M21 3H3c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H3V5h18v14zm-10-7h9v6h-9z"/>
          </svg>
        </button>
        <button class="theater-btn">
          <svg class="tall" viewBox="0 0 24 24">
            <path fill="currentColor" d="M19 6H5c-1.1 0-2 .9-2 2v8c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm0 10H5V8h14v8z"/>
          </svg>
          <svg class="wide" viewBox="0 0 24 24">
            <path fill="currentColor" d="M19 7H5c-1.1 0-2 .9-2 2v6c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V9c0-1.1-.9-2-2-2zm0 8H5V9h14v6z"/>
          </svg>
        </button>
        <button class="full-screen-btn">
          <svg class="open" viewBox="0 0 24 24">
            <path fill="currentColor" d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z"/>
          </svg>
          <svg class="close" viewBox="0 0 24 24">
            <path fill="currentColor" d="M5 16h3v3h2v-5H5v2zm3-8H5v2h5V5H8v3zm6 11h2v-3h3v-2h-5v5zm2-11V5h-2v5h5V8h-3z"/>
          </svg>
        </button>
      </div>
    </div>
    <video width="140%" autoplay src="{{ video_src }}">
      <track kind="captions" srclang="en" src="assets/subtitles.vtt">
    </video>
  </div>
                </div>
            </div>
            {% if authenticated and current_user.id|to_int == current_video.author|to_int or current_user.id == 1 %}
            <div style="margin-bottom: 10px">
                <a href="/edit_video/{{ current_video.id }}" class="btn btn-warning" role="button">Изменить видео</a>
                <a href="/delete_video/{{ current_video.id }}" class="btn btn-danger" role="button">Удалить видео</a>
            </div>
            {% endif %}
            <div class="row">
                <div class="col-auto">
                    <h3>
                        {{ current_video.title }}
                    </h3>
                </div>
                <div class="col-auto">
                    <button onclick="like()" class="btn btn-outline-danger btn-sm {% if like %} active {% endif %}" type="submit" name="like" id="like" {% if not authenticated or current_user.id == current_video.author %} disabled {% endif %}>
                        <svg xmlns="http://www.w3.org/2000/svg" height="16px" viewBox="0 -960 960 960" width="16px" fill="#5f6368"><path d="M840-640q32 0 56 24t24 56v80q0 7-2 15t-4 15L794-168q-9 20-30 34t-44 14H280v-520l240-238q15-15 35.5-17.5T595-888q19 10 28 28t4 37l-45 183h258Zm-480 34v406h360l120-280v-80H480l54-220-174 174ZM160-120q-33 0-56.5-23.5T80-200v-360q0-33 23.5-56.5T160-640h120v80H160v360h120v80H160Zm200-80v-406 406Z"></path></svg>
                        <span id="likes">{{ current_video.likes }}</span>
                    </button>
                </div>
            </div>
            <div class="row">
                <div class="col-auto">
                    <h4>
                    <img src="{{ avatar_url }}" alt="Avatar" class="img-fluid rounded-circle m-2" style="width:80px; height:80px;">
                        <a href="/user/{{ author.id }}" class="text-decoration-none text-dark">{{ author.name }} {{ author.surname }} </a>
                    </h4>
                </div>
                <div class="col-auto">
                    <button onclick="follow()" class="btn btn-outline-danger btn-sm {% if subscription %} active {% endif %}" type="submit" name="follow" id="follow" {% if not authenticated or current_user.id == current_video.author %} disabled {% endif %}>
                        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-person-plus-fill" viewBox="0 0 16 16">
                            <path d="M1 14s-1 0-1-1 1-4 6-4 6 3 6 4-1 1-1 1H1zm5-6a3 3 0 1 0 0-6 3 3 0 0 0 0 6z"/>
                            <path fill-rule="evenodd" d="M13.5 5a.5.5 0 0 1 .5.5V7h1.5a.5.5 0 0 1 0 1H14v1.5a.5.5 0 0 1-1 0V8h-1.5a.5.5 0 0 1 0-1H13V5.5a.5.5 0 0 1 .5-.5z"/>
                        </svg>
                        <span id="followers">{{ author.followers }}</span>
                    </button>
                </div>
            </div>



            <div class="row" style="margin-top: 10px">
                <div class="col">
                    {% autoescape false %}
                    <p style="color: #808080">{{ current_video.description }}</p>
                    {% endautoescape %}
                </div>
            </div>
            <div class="row mt-5">
            <div class="row" style="margin-top: 10px">
    {% if pinned_comment %}
        <div class="alert alert-info">
            <strong>Закрепленный комментарий</strong>
            <div class="media mb-3">

                <div class="media-body">

                    <img src="{{ url_for('static', filename='avatars/' ~ pinned_comment.user.avatar) }}" alt="Avatar" class="mr-3 rounded-circle" style="width:50px; height:50px;"><h5 class="mt-0">{{ pinned_comment.user.name }} {{ pinned_comment.user.surname }}</h5>
                    <p>{{ pinned_comment.content }}</p>
                    <small class="text-muted">{{ pinned_comment.datetime.strftime('%Y-%m-%d %H:%M') }}</small>
                </div>
            </div>
        </div>
        {% endif %}

        <!-- Форма добавления комментария -->
        <h4>Комментарии</h4>
        {% if authenticated and not current_user.is_blocked %}
        <form action="" method="post" id="comment-form">
            {{ form.hidden_tag() }}
            <div class="mb-3">
                {{ form.content(class="form-control", placeholder="Ваш комментарий...") }}
                {{ form.parent_id(value=0) }}  <!-- Скрытое поле для parent_id -->
                {% for error in form.content.errors %}
                <div class="alert alert-danger" role="alert">
                    {{ error }}
                </div>
                {% endfor %}
            </div>
            <button type="submit" class="btn btn-primary">Отправить</button>
        </form>
        {% elif authenticated and current_user.is_blocked %}
        <p>Ваш аккаунт заблокирован, вы не можете оставлять комментарии.</p>
        {% else %}
        <p>Вы должны <a href="{{ url_for('login') }}">войти</a> или <a href="{{ url_for('register') }}">зарегистрироваться</a>, чтобы оставить комментарий.</p>
        {% endif %}
<div class="row" style="margin-top: 10px">
        <!-- Список комментариев -->
       {% macro render_comment(comment, depth=0) %}
    <!-- Если комментарий имеет родителя, показываем информацию "отвечает на ..." -->
    {% if comment.parent %}
        <div class="text-muted" style="margin-left: {{ depth * 20 }}px;">
            Отвечает на {{ comment.parent.user.name }} {{ comment.parent.user.surname }}:
            "{{ comment.parent.content[:50] }}{% if comment.parent.content|length > 50 %}...{% endif %}"
        </div>
    {% endif %}
    <div class="media mb-3" style="margin-left: {{ depth * 20 }}px;">
        <img src="{{ url_for('static', filename='avatars/' ~ comment.user.avatar) }}" alt="Avatar" class="mr-3 rounded-circle me-3" style="width:50px; height:50px;">
        <div class="media-body">
            <h5 class="mt-0">
                {{ comment.user.name }} {{ comment.user.surname }}
            </h5>
            <p>{{ comment.content }}</p>
            <small class="text-muted">{{ comment.datetime.strftime('%Y-%m-%d %H:%M') }}</small>

            <!-- Кнопки комментария -->
            <div class="d-flex align-items-center">
                <!-- Кнопка лайка комментария -->
                <button onclick="likeComment({{ comment.id }})" class="btn btn-sm btn-outline-primary me-2 {% if current_user.is_authenticated and (comment.id in user_comment_likes) %}active{% endif %}" id="like-comment-btn-{{ comment.id }}">
                    Лайк <span id="comment-likes-{{ comment.id }}">{{ comment.likes }}</span>
                </button>

                <!-- Кнопка ответа -->
                {% if authenticated and not current_user.is_blocked %}
                <a href="#" onclick="replyToComment({{ comment.id }}, '{{ comment.user.name }}'); return false;" class="me-2">Ответить</a>
                {% endif %}

                <!-- Кнопка закрепления (для автора видео) -->


                <!-- Кнопка удаления (для автора комментария) -->
                {% if current_user.is_authenticated and current_user.id == comment.user_id %}
                <form action="{{ url_for('delete_comment', comment_id=comment.id) }}" method="post" style="display:inline;">
                    <button type="submit" class="btn btn-sm btn-outline-danger">Удалить</button>
                </form>
                {% endif %}
            </div>

            <!-- Рекурсивно отображаем ответы -->
            {% if comment.replies %}
                {% for reply in comment.replies %}
                    {{ render_comment(reply, depth + 1) }}
                {% endfor %}
            {% endif %}
        </div>
    </div>
{% endmacro %}
        {% if comments_enabled %}
        <!-- Отображение комментариев -->
        {% for comment in comments %}
            {% if not comment.parent_id %}
                {{ render_comment(comment) }}
            {% endif %}
        {% endfor %}
          {% else %}
    <!-- Сообщение при отключенных комментариях -->
    <p>Комментарии отключены для этого видео.</p>

         {% endif %}

    </div>

    <!-- Боковая панель с другими видео -->
    <div class="col-3">
        <!-- (Ваш существующий код боковой панели здесь) -->
        <!-- ... -->
    </div>
</div>

<!-- Скрипты для обработки действий с комментариями -->
<script>
    // Функция для лайка комментария
    function likeComment(commentId) {
        fetch('/api/comment_like/' + commentId, {
            method: 'POST'
        })
        .then(response => response.json())
        .then(data => {
            if (data.success) {
                let likeBtn = document.getElementById('like-comment-btn-' + commentId);
                let likesCount = document.getElementById('comment-likes-' + commentId);
                likesCount.innerText = data.likes;
                likeBtn.classList.toggle('active');
            } else {
                console.error(data.error);
            }
        });
    }

    // Функция для ответа на комментарий
    function replyToComment(commentId, userName) {
        const replyForm = document.getElementById('comment-form');
        replyForm.parent_id.value = commentId;
        replyForm.content.placeholder = 'Ответить ' + userName;
        replyForm.content.focus();
    }

    // Функция для закрепления комментария
    function pinComment(commentId) {
        fetch('/api/pin_comment/' + commentId, {
            method: 'POST'
        })
        .then(response => response.json())
        .then(data => {
            if (data.success) {
                // Обновляем страницу для отображения изменений
                location.reload();
            } else {
                console.error(data.error);
            }
        });
    }

    // Функция для подписки/отписки на автора видео
    function toggleSubscription() {
        fetch('/api/follow/{{ current_video.author }}', {
            method: 'POST'
        })
        .then(response => response.json())
        .then(data => {
            if (data.success) {
                let subscribeBtn = document.getElementById('subscribe-btn');
                subscribeBtn.classList.toggle('active');
                subscribeBtn.innerText = subscribeBtn.classList.contains('active') ? 'Отписаться' : 'Подписаться';
            } else {
                console.error(data.error);
            }
        });
    }
</script>
            <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
            <script type=text/javascript>
                function follow() {
                    var follow = document.getElementById("follow");
                    var unfollow = document.getElementById("unfollow");
                    var followers = document.getElementById("followers");
                    if ( follow.classList.contains('active') )
                    {
                        follow.classList.remove("active");
                        followers.innerHTML = parseInt(followers.innerText) - 1;
                        $.post('/api/not_follow/{{ current_video.author }}');
                    }
                    else
                    {
                        follow.classList.add("active");
                        followers.innerHTML = parseInt(followers.innerText) + 1;
                        $.post('/api/follow/{{ current_video.author }}');
                        if ( unfollow.classList.contains('active') )
                        {
                            unfollow.classList.remove("active");
                            followers.innerHTML = parseInt(followers.innerText) + 1;
                        }
                    }
                }

                function like() {
                    var like = document.getElementById("like");
                    var dislike = document.getElementById("dislike");
                    var likes = document.getElementById("likes");
                    if ( like.classList.contains('active') )
                    {
                        like.classList.remove("active");
                        likes.innerHTML = parseInt(likes.innerText) - 1;
                        $.post('/api/not_like/{{ current_video.id }}');
                    }
                    else
                    {
                        like.classList.add("active");
                        likes.innerHTML = parseInt(likes.innerText) + 1;
                        $.post('/api/like/{{ current_video.id }}');
                        if ( dislike.classList.contains('active') )
                        {
                            dislike.classList.remove("active");
                            likes.innerHTML = parseInt(likes.innerText) + 1;
                        }
                    }
                }





const playPauseBtn = document.querySelector(".play-pause-btn")
const theaterBtn = document.querySelector(".theater-btn")
const fullScreenBtn = document.querySelector(".full-screen-btn")
const miniPlayerBtn = document.querySelector(".mini-player-btn")
const muteBtn = document.querySelector(".mute-btn")
const captionsBtn = document.querySelector(".captions-btn")
const speedBtn = document.querySelector(".speed-btn")
const currentTimeElem = document.querySelector(".current-time")
const totalTimeElem = document.querySelector(".total-time")
const previewImg = document.querySelector(".preview-img")
const thumbnailImg = document.querySelector(".thumbnail-img")
const volumeSlider = document.querySelector(".volume-slider")
const videoContainer = document.querySelector(".video-container")
const timelineContainer = document.querySelector(".timeline-container")
const video = document.querySelector("video")

document.addEventListener("keydown", e => {
  const tagName = document.activeElement.tagName.toLowerCase()

  if (tagName === "input") return

  switch (e.key.toLowerCase()) {
    case " ":
      if (tagName === "button") return
    case "k":
      togglePlay()
      break
    case "f":
      toggleFullScreenMode()
      break
    case "t":
      toggleTheaterMode()
      break
    case "i":
      toggleMiniPlayerMode()
      break
    case "m":
      toggleMute()
      break
    case "arrowleft":
    case "j":
      skip(-5)
      break
    case "arrowright":
    case "l":
      skip(5)
      break
    case "c":
      toggleCaptions()
      break
  }
})

// Timeline
timelineContainer.addEventListener("mousemove", handleTimelineUpdate)
timelineContainer.addEventListener("mousedown", toggleScrubbing)
document.addEventListener("mouseup", e => {
  if (isScrubbing) toggleScrubbing(e)
})
document.addEventListener("mousemove", e => {
  if (isScrubbing) handleTimelineUpdate(e)
})

let isScrubbing = false
let wasPaused = false
function toggleScrubbing(e) {
  const rect = timelineContainer.getBoundingClientRect()
  const percent = Math.min(Math.max(0, e.x - rect.x), rect.width) / rect.width
  isScrubbing = (e.buttons & 1) === 1
  videoContainer.classList.toggle("scrubbing", isScrubbing)
  if (isScrubbing) {
    wasPaused = video.paused
    video.pause()
  } else {
    video.currentTime = percent * video.duration
    if (!wasPaused) video.play()
  }

  handleTimelineUpdate(e)
}

function handleTimelineUpdate(e) {
  const rect = timelineContainer.getBoundingClientRect()
  const percent = Math.min(Math.max(0, e.x - rect.x), rect.width) / rect.width
  const previewImgNumber = Math.max(
    1,
    Math.floor((percent * video.duration) / 10)
  )
  const previewImgSrc = "/static/pre/{{ current_video.id }}.jpg"
  previewImg.src = previewImgSrc
  timelineContainer.style.setProperty("--preview-position", percent)

  if (isScrubbing) {
    e.preventDefault()
    thumbnailImg.src = previewImgSrc
    timelineContainer.style.setProperty("--progress-position", percent)
  }
}

// Playback Speed
speedBtn.addEventListener("click", changePlaybackSpeed)

function changePlaybackSpeed() {
  let newPlaybackRate = video.playbackRate + 0.25
  if (newPlaybackRate > 3) newPlaybackRate = 0.25
  video.playbackRate = newPlaybackRate
  speedBtn.textContent = `${newPlaybackRate}x`
}

// Captions
const captions = video.textTracks[0]
captions.mode = "hidden"

captionsBtn.addEventListener("click", toggleCaptions)

function toggleCaptions() {
  const isHidden = captions.mode === "hidden"
  captions.mode = isHidden ? "showing" : "hidden"
  videoContainer.classList.toggle("captions", isHidden)
}

// Duration
video.addEventListener("loadeddata", () => {
  totalTimeElem.textContent = formatDuration(video.duration)
})

video.addEventListener("timeupdate", () => {
  currentTimeElem.textContent = formatDuration(video.currentTime)
  const percent = video.currentTime / video.duration
  timelineContainer.style.setProperty("--progress-position", percent)
})

const leadingZeroFormatter = new Intl.NumberFormat(undefined, {
  minimumIntegerDigits: 2,
})
function formatDuration(time) {
  const seconds = Math.floor(time % 60)
  const minutes = Math.floor(time / 60) % 60
  const hours = Math.floor(time / 3600)
  if (hours === 0) {
    return `${minutes}:${leadingZeroFormatter.format(seconds)}`
  } else {
    return `${hours}:${leadingZeroFormatter.format(
      minutes
    )}:${leadingZeroFormatter.format(seconds)}`
  }
}

function skip(duration) {
  video.currentTime += duration
}

// Volume
muteBtn.addEventListener("click", toggleMute)
volumeSlider.addEventListener("input", e => {
  video.volume = e.target.value
  video.muted = e.target.value === 0
})

function toggleMute() {
  video.muted = !video.muted
}

video.addEventListener("volumechange", () => {
  volumeSlider.value = video.volume
  let volumeLevel
  if (video.muted || video.volume === 0) {
    volumeSlider.value = 0
    volumeLevel = "muted"
  } else if (video.volume >= 0.5) {
    volumeLevel = "high"
  } else {
    volumeLevel = "low"
  }

  videoContainer.dataset.volumeLevel = volumeLevel
})

// View Modes
theaterBtn.addEventListener("click", toggleTheaterMode)
fullScreenBtn.addEventListener("click", toggleFullScreenMode)
miniPlayerBtn.addEventListener("click", toggleMiniPlayerMode)

function toggleTheaterMode() {
  videoContainer.classList.toggle("theater")
}

function toggleFullScreenMode() {
  if (document.fullscreenElement == null) {
    videoContainer.requestFullscreen()
  } else {
    document.exitFullscreen()
  }
}

function toggleMiniPlayerMode() {
  if (videoContainer.classList.contains("mini-player")) {
    document.exitPictureInPicture()
  } else {
    video.requestPictureInPicture()
  }
}

document.addEventListener("fullscreenchange", () => {
  videoContainer.classList.toggle("full-screen", document.fullscreenElement)
})

video.addEventListener("enterpictureinpicture", () => {
  videoContainer.classList.add("mini-player")
})

video.addEventListener("leavepictureinpicture", () => {
  videoContainer.classList.remove("mini-player")
})

// Play/Pause
playPauseBtn.addEventListener("click", togglePlay)
video.addEventListener("click", togglePlay)

function togglePlay() {
  video.paused ? video.play() : video.pause()
}

video.addEventListener("play", () => {
  videoContainer.classList.remove("paused")
})

video.addEventListener("pause", () => {
  videoContainer.classList.add("paused")
})
            </script>
        </div>
        <style>
        *, *::before, *::after {
  box-sizing: border-box;
}

body {
  margin: 0;
}

.video-container {
  position: relative;
  width: 90%;
  max-width: 1000px;
  display: flex;
  justify-content: center;
  margin-inline: auto;
  background-color: black;
}

.video-container.theater,
.video-container.full-screen {
  max-width: initial;
  width: 100%;
}

.video-container.theater {
  max-height: 90vh;
}

.video-container.full-screen {
  max-height: 100vh;
}

video {
  width: 100%;
}

.video-controls-container {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  color: white;
  z-index: 100;
  opacity: 0;
  transition: opacity 150ms ease-in-out;
}

.video-controls-container::before {
  content: "";
  position: absolute;
  bottom: 0;
  background: linear-gradient(to top, rgba(0, 0, 0, .75), transparent);
  width: 100%;
  aspect-ratio: 6 / 1;
  z-index: -1;
  pointer-events: none;
}

.video-container:hover .video-controls-container,
.video-container:focus-within .video-controls-container,
.video-container.paused .video-controls-container {
  opacity: 1;
}

.video-controls-container .controls {
  display: flex;
  gap: .5rem;
  padding: .25rem;
  align-items: center;
}

.video-controls-container .controls button {
  background: none;
  border: none;
  color: inherit;
  padding: 0;
  height: 30px;
  width: 30px;
  font-size: 1.1rem;
  cursor: pointer;
  opacity: .85;
  transition: opacity 150ms ease-in-out;
}

.video-controls-container .controls button:hover {
  opacity: 1;
}

.video-container.paused .pause-icon {
  display: none;
}

.video-container:not(.paused) .play-icon {
  display: none;
}

.video-container.theater .tall {
  display: none;
}

.video-container:not(.theater) .wide {
  display: none;
}

.video-container.full-screen .open {
  display: none;
}

.video-container:not(.full-screen) .close {
  display: none;
}

.volume-high-icon,
.volume-low-icon,
.volume-muted-icon {
  display: none;
}

.video-container[data-volume-level="high"] .volume-high-icon {
  display: block;
}

.video-container[data-volume-level="low"] .volume-low-icon {
  display: block;
}

.video-container[data-volume-level="muted"] .volume-muted-icon {
  display: block;
}

.volume-container {
  display: flex;
  align-items: center;
}

.volume-slider {
  width: 0;
  transform-origin: left;
  transform: scaleX(0);
  transition: width 150ms ease-in-out, transform 150ms ease-in-out;
  background: linear-gradient(45deg, red, orange, yellow, green, blue, indigo, violet, red);
}

.volume-container:hover .volume-slider,
.volume-slider:focus-within {
  width: 100px;
  transform: scaleX(1);
}

.duration-container {
  display: flex;
  align-items: center;
  gap: .25rem;
  flex-grow: 1;
}

.video-container.captions .captions-btn {
  border-bottom: 3px solid red;
}

.video-controls-container .controls button.wide-btn {
  width: 50px;
}

.timeline-container {
  height: 7px;
  margin-inline: .5rem;
  cursor: pointer;
  display: flex;
  align-items: center;
}

.timeline {
  background-color: rgba(100, 100, 100, .5);
  height: 3px;
  width: 100%;
  position: relative
}

.timeline::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  right: calc(100% - var(--preview-position) * 100%);
  background-color: rgb(150, 150, 150);
  display: none;
}

.timeline::after {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  right: calc(100% - var(--progress-position) * 100%);
  background: linear-gradient(45deg, red, orange, yellow, green, blue, indigo, violet, red);
}

.timeline .thumb-indicator {
  --scale: 0;
  position: absolute;
  transform: translateX(-50%) scale(var(--scale));
  height: 200%;
  top: -50%;
  left: calc(var(--progress-position) * 100%);
  background-color: red;
  border-radius: 50%;
  transition: transform 150ms ease-in-out;
  aspect-ratio: 1 / 1;
}

.timeline .preview-img {
  position: absolute;
  height: 80px;
  aspect-ratio: 16 / 9;
  top: -1rem;
  transform: translate(-50%, -100%);
  left: calc(var(--preview-position) * 100%);
  border-radius: .25rem;
  border: 2px solid white;
  display: none;
}

.thumbnail-img {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  width: 100%;
  height: 100%;
  display: none;
}

.video-container.scrubbing .thumbnail-img {
  display: block;
}

.video-container.scrubbing .preview-img,
.timeline-container:hover .preview-img {
  display: block;
}

.video-container.scrubbing .timeline::before,
.timeline-container:hover .timeline::before {
  display: block;
}

.video-container.scrubbing .thumb-indicator,
.timeline-container:hover .thumb-indicator {
  --scale: 1;
}

.video-container.scrubbing .timeline,
.timeline-container:hover .timeline {
  height: 100%;
}
        </style>
        <div class="col-3">
            {% for vid in last_videos %}
            <div class="row">
                <a href="/video/{{ vid.id }}"><img src="/static/pre/{{ vid.id }}.jpg" style="width: 100%"></a>
                <p><a class="text-decoration-none text-dark" href="/video/{{ vid.id }}">{{ vid.title }}</a> - <a class="text-decoration-none text-dark" href="/user/{{ db_sess.query(User).filter(User.id == vid.author).first().id }}">{{ db_sess.query(User).filter(User.id == vid.author).first().name }} {{ db_sess.query(User).filter(User.id == vid.author).first().surname }}</a></p>
            </div>
            {% endfor %}
        </div>
    </div>
    <div class="col-3">
            {% for vid in last_videos %}
            <div class="row">
                <a href="/video/{{ vid.id }}"><img src="/static/pre/{{ vid.id }}.jpg" style="width: 100%"></a>
                <p><a class="text-decoration-none text-dark" href="/video/{{ vid.id }}">{{ vid.title }}</a> - <a class="text-decoration-none text-dark" href="/user/{{ db_sess.query(User).filter(User.id == vid.author).first().id }}">{{ db_sess.query(User).filter(User.id == vid.author).first().name }} {{ db_sess.query(User).filter(User.id == vid.author).first().surname }}</a></p>
            </div>
            {% endfor %}
        </div>
{% endblock %}
i want to make the comments disabling-enabling next to button edit video (only for author or admin)