art upload optimization

This commit is contained in:
aneuhmanh 2025-02-19 22:01:56 +02:00
parent 779339d2ad
commit 7baff5ec76
2 changed files with 41 additions and 65 deletions

65
app.py
View File

@ -24,8 +24,8 @@ from wtforms.validators import DataRequired, Length, EqualTo, ValidationError, R
from wtforms import StringField, PasswordField, SubmitField from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, EqualTo, Regexp from wtforms.validators import DataRequired, EqualTo, Regexp
from flask_wtf import FlaskForm, RecaptchaField from flask_wtf import FlaskForm, RecaptchaField
from dotenv import load_dotenv
from dotenv import load_dotenv, find_dotenv from dotenv import load_dotenv, find_dotenv
import aiofiles.os
dotenv_path = find_dotenv() dotenv_path = find_dotenv()
load_dotenv(dotenv_path, override=True) load_dotenv(dotenv_path, override=True)
@ -47,7 +47,7 @@ app.config.update(
'avatars': 'static/avatars/', 'avatars': 'static/avatars/',
'banners': 'static/banners/', 'banners': 'static/banners/',
'comics': 'static/comics', 'comics': 'static/comics',
'comicthumbs': 'static/comicthumbs', 'comicthumbs': 'static/comicthumbs/',
'posts': 'static/posts/' 'posts': 'static/posts/'
}, },
ALLOWED_IMAGE_EXTENSIONS={'png', 'jpg', 'jpeg', 'gif', 'webp'}, ALLOWED_IMAGE_EXTENSIONS={'png', 'jpg', 'jpeg', 'gif', 'webp'},
@ -557,87 +557,65 @@ class UploadForm(FlaskForm):
validators=[DataRequired(message="You must agree with the publication rules.")]) validators=[DataRequired(message="You must agree with the publication rules.")])
submit = SubmitField('Upload') submit = SubmitField('Upload')
def convert_to_webp(image_file): async def convert_to_webp(image_file):
loop = asyncio.get_event_loop()
return await loop.run_in_executor(None, _sync_convert_to_webp, image_file)
img = PILImage.open(image_file) def _sync_convert_to_webp(image_file):
with PILImage.open(image_file) as img:
output = io.BytesIO() output = io.BytesIO()
img.convert("RGB").save(output, format="WEBP", quality=90, optimize=True) img.convert("RGB").save(output, format="WEBP", quality=90, optimize=True)
output.seek(0) output.seek(0)
return output return output
@app.route('/upload', methods=['GET', 'POST']) @app.route('/upload', methods=['GET', 'POST'])
@login_required @login_required
def upload(): async def upload():
form = UploadForm() form = UploadForm()
if form.validate_on_submit(): if form.validate_on_submit():
image_file = form.image_file.data image_file = form.image_file.data
tags = form.tags.data tags = form.tags.data
if not (allowed_file(image_file.filename, app.config['ALLOWED_IMAGE_EXTENSIONS']) and
if image_file: await check_file_size(image_file, app.config['MAX_IMAGE_SIZE'])):
if not allowed_file(image_file.filename, app.config['ALLOWED_IMAGE_EXTENSIONS']):
return redirect(url_for('upload')) return redirect(url_for('upload'))
if not check_file_size(image_file, app.config['MAX_IMAGE_SIZE']):
return redirect(url_for('upload'))
unique_filename = f"{uuid.uuid4().hex}.webp" unique_filename = f"{uuid.uuid4().hex}.webp"
filepath = os.path.join(app.config['UPLOAD_FOLDER']['images'], unique_filename) filepath = os.path.join(app.config['UPLOAD_FOLDER']['images'], unique_filename)
if os.path.exists(filepath): if os.path.exists(filepath):
return redirect(url_for('upload')) return redirect(url_for('upload'))
webp_image = await convert_to_webp(image_file)
webp_image = convert_to_webp(image_file) async with aiofiles.open(filepath, 'wb') as f:
await f.write(webp_image.read())
try:
with open(filepath, 'wb') as f:
f.write(webp_image.read())
except Exception as e:
return redirect(url_for('upload'))
img = Image(image_file=unique_filename, username=current_user.username, tags=tags, cookie_votes=0) img = Image(image_file=unique_filename, username=current_user.username, tags=tags, cookie_votes=0)
db.session.add(img) db.session.add(img)
user_cookie = Cookies.query.filter_by(username=current_user.username).first() user_cookie = Cookies.query.filter_by(username=current_user.username).first()
if user_cookie: if user_cookie:
user_cookie.cookies += 1 user_cookie.cookies += 1
else: else:
user_cookie = Cookies(username=current_user.username, cookies=1) user_cookie = Cookies(username=current_user.username, cookies=1)
db.session.add(user_cookie) db.session.add(user_cookie)
try:
db.session.commit() db.session.commit()
except Exception as e:
db.session.rollback()
return redirect(url_for('upload'))
return redirect(url_for('index')) return redirect(url_for('index'))
else:
return redirect(url_for('upload'))
return render_template('upload.html', form=form) return render_template('upload.html', form=form)
def allowed_file(filename, allowed_extensions): def allowed_file(filename, allowed_extensions):
return '.' in filename and filename.rsplit('.', 1)[1].lower() in allowed_extensions return '.' in filename and filename.rsplit('.', 1)[1].lower() in allowed_extensions
def check_file_size(file, max_size): async def check_file_size(file, max_size):
loop = asyncio.get_event_loop()
return await loop.run_in_executor(None, _sync_check_file_size, file, max_size)
def _sync_check_file_size(file, max_size):
file.seek(0, os.SEEK_END) file.seek(0, os.SEEK_END)
file_size = file.tell() file_size = file.tell()
file.seek(0) file.seek(0)
return file_size <= max_size return file_size <= max_size
def generate_unique_filename(filename, upload_folder): async def generate_unique_filename(filename, upload_folder):
base, ext = os.path.splitext(secure_filename(filename)) base, ext = os.path.splitext(secure_filename(filename))
while True:
unique_filename = f"{base}_{uuid.uuid4().hex}{ext}" unique_filename = f"{base}_{uuid.uuid4().hex}{ext}"
file_path = os.path.join(upload_folder, unique_filename) file_path = os.path.join(upload_folder, unique_filename)
if not await aiofiles.os.path.exists(file_path):
while os.path.exists(file_path):
unique_filename = f"{base}_{uuid.uuid4().hex}{ext}"
file_path = os.path.join(upload_folder, unique_filename)
return unique_filename return unique_filename
class UploadVideoForm(FlaskForm): class UploadVideoForm(FlaskForm):
@ -1595,7 +1573,6 @@ def buy_item(item_id):
db.session.commit() db.session.commit()
return redirect(url_for('shop')) return redirect(url_for('shop'))
if __name__ == '__main__': if __name__ == '__main__':
with app.app_context(): with app.app_context():
db.create_all() db.create_all()

View File

@ -133,8 +133,7 @@
<div class="vote-section"> <div class="vote-section">
<p>Votes: {{ content.cookie_votes }} 🍪</p> <p>Votes: {{ content.cookie_votes }} 🍪</p>
{% if current_user.is_authenticated %} {% if current_user.is_authenticated %}
<form action="{{ url_for('vote_content', content_type=content_type, content_id=content.id) }}" <form action="{{ url_for('vote_' + content_type, **({'image_id': content.id} if content_type == 'art' else {'video_id': content.id} if content_type == 'video' else {'comic_id': content.id})) }}" method="POST">
method="POST">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"> <input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<button type="submit" class="button">Vote</button> <button type="submit" class="button">Vote</button>
</form> </form>