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

103
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.validators import DataRequired, EqualTo, Regexp
from flask_wtf import FlaskForm, RecaptchaField
from dotenv import load_dotenv
from dotenv import load_dotenv, find_dotenv
import aiofiles.os
dotenv_path = find_dotenv()
load_dotenv(dotenv_path, override=True)
@ -47,7 +47,7 @@ app.config.update(
'avatars': 'static/avatars/',
'banners': 'static/banners/',
'comics': 'static/comics',
'comicthumbs': 'static/comicthumbs',
'comicthumbs': 'static/comicthumbs/',
'posts': 'static/posts/'
},
ALLOWED_IMAGE_EXTENSIONS={'png', 'jpg', 'jpeg', 'gif', 'webp'},
@ -557,88 +557,66 @@ class UploadForm(FlaskForm):
validators=[DataRequired(message="You must agree with the publication rules.")])
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)
output = io.BytesIO()
img.convert("RGB").save(output, format="WEBP", quality=90, optimize=True)
output.seek(0)
return output
def _sync_convert_to_webp(image_file):
with PILImage.open(image_file) as img:
output = io.BytesIO()
img.convert("RGB").save(output, format="WEBP", quality=90, optimize=True)
output.seek(0)
return output
@app.route('/upload', methods=['GET', 'POST'])
@login_required
def upload():
async def upload():
form = UploadForm()
if form.validate_on_submit():
image_file = form.image_file.data
tags = form.tags.data
if image_file:
if not allowed_file(image_file.filename, app.config['ALLOWED_IMAGE_EXTENSIONS']):
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"
filepath = os.path.join(app.config['UPLOAD_FOLDER']['images'], unique_filename)
if os.path.exists(filepath):
return redirect(url_for('upload'))
webp_image = convert_to_webp(image_file)
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)
db.session.add(img)
user_cookie = Cookies.query.filter_by(username=current_user.username).first()
if user_cookie:
user_cookie.cookies += 1
else:
user_cookie = Cookies(username=current_user.username, cookies=1)
db.session.add(user_cookie)
try:
db.session.commit()
except Exception as e:
db.session.rollback()
return redirect(url_for('upload'))
return redirect(url_for('index'))
else:
if not (allowed_file(image_file.filename, app.config['ALLOWED_IMAGE_EXTENSIONS']) and
await check_file_size(image_file, app.config['MAX_IMAGE_SIZE'])):
return redirect(url_for('upload'))
unique_filename = f"{uuid.uuid4().hex}.webp"
filepath = os.path.join(app.config['UPLOAD_FOLDER']['images'], unique_filename)
if os.path.exists(filepath):
return redirect(url_for('upload'))
webp_image = await convert_to_webp(image_file)
async with aiofiles.open(filepath, 'wb') as f:
await f.write(webp_image.read())
img = Image(image_file=unique_filename, username=current_user.username, tags=tags, cookie_votes=0)
db.session.add(img)
user_cookie = Cookies.query.filter_by(username=current_user.username).first()
if user_cookie:
user_cookie.cookies += 1
else:
user_cookie = Cookies(username=current_user.username, cookies=1)
db.session.add(user_cookie)
db.session.commit()
return redirect(url_for('index'))
return render_template('upload.html', form=form)
def allowed_file(filename, 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_size = file.tell()
file.seek(0)
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))
unique_filename = f"{base}_{uuid.uuid4().hex}{ext}"
file_path = os.path.join(upload_folder, unique_filename)
while os.path.exists(file_path):
while True:
unique_filename = f"{base}_{uuid.uuid4().hex}{ext}"
file_path = os.path.join(upload_folder, unique_filename)
return unique_filename
if not await aiofiles.os.path.exists(file_path):
return unique_filename
class UploadVideoForm(FlaskForm):
video_file = FileField('Video File', validators=[DataRequired()])
@ -1595,7 +1573,6 @@ def buy_item(item_id):
db.session.commit()
return redirect(url_for('shop'))
if __name__ == '__main__':
with app.app_context():
db.create_all()

View File

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