This commit is contained in:
aneuhmanh 2025-02-24 13:07:32 +02:00
parent 4f2a867df7
commit 07c2cc11c3
3 changed files with 69 additions and 30 deletions

78
app.py
View File

@ -54,7 +54,7 @@ app.config.update(
ALLOWED_IMAGE_EXTENSIONS={'png', 'jpg', 'jpeg', 'gif', 'webp'}, ALLOWED_IMAGE_EXTENSIONS={'png', 'jpg', 'jpeg', 'gif', 'webp'},
ALLOWED_VIDEO_EXTENSIONS={'mp4', 'avi', 'mov'}, ALLOWED_VIDEO_EXTENSIONS={'mp4', 'avi', 'mov'},
MAX_IMAGE_SIZE=15 * 1024 * 1024, MAX_IMAGE_SIZE=15 * 1024 * 1024,
MAX_VIDEO_SIZE=1 * 1024 * 1024 * 1024 MAX_VIDEO_SIZE=10 * 1024 * 1024 * 1024
) )
def allowed_file(filename, allowed_extensions): def allowed_file(filename, allowed_extensions):
@ -157,12 +157,24 @@ class Comic(db.Model):
comic_folder = db.Column(db.String(100), nullable=False) comic_folder = db.Column(db.String(100), nullable=False)
comic_thumbnail_file = db.Column(db.String(100), nullable=False) comic_thumbnail_file = db.Column(db.String(100), nullable=False)
username = db.Column(db.String(20), db.ForeignKey('user.username'), nullable=False) username = db.Column(db.String(20), db.ForeignKey('user.username'), nullable=False)
name = db.Column(db.String(100), nullable=False) name = db.Column(db.String(100), nullable=False, unique=True)
publication_date = db.Column(db.DateTime, default=datetime.utcnow) publication_date = db.Column(db.DateTime, default=datetime.utcnow)
tags = db.Column(db.String(100), nullable=True) tags = db.Column(db.String(100), nullable=True)
cookie_votes = db.Column(db.Integer, default=0) cookie_votes = db.Column(db.Integer, default=0)
comments = db.relationship('Comments', back_populates='comic', overlaps="comic_link") comments = db.relationship('Comments', back_populates='comic', overlaps="comic_link")
pages = db.relationship('ComicPage', back_populates='comic', cascade="all, delete-orphan")
class ComicPage(db.Model):
__tablename__ = 'comic_pages'
id = db.Column(db.Integer, primary_key=True)
comic_id = db.Column(db.Integer, db.ForeignKey('comics.id', ondelete='CASCADE'), nullable=False)
page_number = db.Column(db.Integer, nullable=False)
file_path = db.Column(db.String(200), nullable=False)
comic = db.relationship('Comic', back_populates='pages')
class ComicVotes(db.Model): class ComicVotes(db.Model):
__tablename__ = 'comic_votes' __tablename__ = 'comic_votes'
@ -644,7 +656,7 @@ async def upload_video():
return redirect(url_for('upload_video')) return redirect(url_for('upload_video'))
video_filename = await generate_unique_filename(video_file.filename, app.config['UPLOAD_FOLDER']['videos']) video_filename = await generate_unique_filename(video_file.filename, app.config['UPLOAD_FOLDER']['videos'])
thumbnail_filename = await generate_unique_filename(video_thumbnail.filename, app.config['UPLOAD_FOLDER']['thumbnails']) thumbnail_filename = f"{uuid.uuid4().hex}.webp"
video_path = os.path.join(app.config['UPLOAD_FOLDER']['videos'], video_filename) video_path = os.path.join(app.config['UPLOAD_FOLDER']['videos'], video_filename)
thumbnail_path = os.path.join(app.config['UPLOAD_FOLDER']['thumbnails'], thumbnail_filename) thumbnail_path = os.path.join(app.config['UPLOAD_FOLDER']['thumbnails'], thumbnail_filename)
@ -652,8 +664,9 @@ async def upload_video():
async with aiofiles.open(video_path, 'wb') as f: async with aiofiles.open(video_path, 'wb') as f:
await f.write(video_file.read()) await f.write(video_file.read())
webp_thumbnail = await convert_to_webp(video_thumbnail)
async with aiofiles.open(thumbnail_path, 'wb') as f: async with aiofiles.open(thumbnail_path, 'wb') as f:
await f.write(video_thumbnail.read()) await f.write(webp_thumbnail.read())
video = Video( video = Video(
video_file=video_filename, video_file=video_filename,
@ -697,22 +710,26 @@ async def comic_upload():
tags=tags tags=tags
) )
db.session.add(new_comic) db.session.add(new_comic)
try: db.session.flush()
db.session.commit()
except IntegrityError:
db.session.rollback()
return render_template('comic_upload.html')
async def save_pages(): async def save_pages():
for p in request.files.getlist('pages[]'): pages = request.files.getlist('pages[]')
for i, p in enumerate(sorted(pages, key=lambda x: x.filename), start=1):
if p: if p:
async with aiofiles.open(os.path.join(cf, secure_filename(p.filename)), 'wb') as f: filename = secure_filename(p.filename)
file_path = os.path.join(cf, filename)
async with aiofiles.open(file_path, 'wb') as f:
await f.write(p.read()) await f.write(p.read())
await save_pages() new_page = ComicPage(comic_id=new_comic.id, page_number=i, file_path=file_path)
db.session.add(new_page)
db.session.commit()
await save_pages()
return redirect(url_for('comics')) return redirect(url_for('comics'))
return render_template('comic_upload.html')
@app.route('/user_pubs/<pub_type>/<username>') @app.route('/user_pubs/<pub_type>/<username>')
def user_pubs(pub_type, username): def user_pubs(pub_type, username):
p = request.args.get('page', 1, type=int) p = request.args.get('page', 1, type=int)
@ -1022,20 +1039,43 @@ def comic_edit(comic_id):
if not os.path.exists(cfp): if not os.path.exists(cfp):
os.makedirs(cfp) os.makedirs(cfp)
comic_pages = sorted(os.listdir(cfp))
form = EmptyForm() form = EmptyForm()
if request.method == 'POST' and form.validate_on_submit(): if request.method == 'POST' and form.validate_on_submit():
action = request.form.get('action') action = request.form.get('action')
if action == 'delete' and (page_to_delete := request.form.get('page')):
os.remove(os.path.join(cfp, page_to_delete)) if action == 'delete' and (page_id := request.form.get('page')):
elif action in ['update', 'add'] and 'new_page' in request.files: page = ComicPage.query.get(page_id)
if page:
os.remove(page.file_path)
db.session.delete(page)
db.session.commit()
elif action == 'update' and (page_id := request.form.get('page')) and 'new_page' in request.files:
new_page = request.files['new_page'] new_page = request.files['new_page']
new_page.save(os.path.join(cfp, secure_filename(new_page.filename))) filename = secure_filename(new_page.filename)
file_path = os.path.join(cfp, filename)
new_page.save(file_path)
page = ComicPage.query.get(page_id)
if page:
os.remove(page.file_path)
page.file_path = file_path
db.session.commit()
elif action == 'add' and 'new_page' in request.files:
new_page = request.files['new_page']
filename = secure_filename(new_page.filename)
file_path = os.path.join(cfp, filename)
new_page.save(file_path)
page_number = (db.session.query(db.func.max(ComicPage.page_number)).filter_by(comic_id=comic.id).scalar() or 0) + 1
db.session.add(ComicPage(comic_id=comic.id, page_number=page_number, file_path=file_path))
db.session.commit()
return redirect(url_for('comic_edit', comic_id=comic.id)) return redirect(url_for('comic_edit', comic_id=comic.id))
return render_template('comic_edit.html', comic=comic, comic_pages=comic_pages, form=form) return render_template('comic_edit.html', comic=comic, comic_pages=comic.pages, form=form)
def update_related_tables(old_username, new_username): def update_related_tables(old_username, new_username):
@ -1570,4 +1610,4 @@ def buy_item(item_id):
if __name__ == '__main__': if __name__ == '__main__':
with app.app_context(): with app.app_context():
db.create_all() db.create_all()
app.run(debug=True) app.run(debug=False)

View File

@ -7,7 +7,6 @@
<link rel="stylesheet" href="{{ url_for('static', filename='css/comic_edit.css') }}"> <link rel="stylesheet" href="{{ url_for('static', filename='css/comic_edit.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}"> <link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
<link rel="icon" href="{{ url_for('static', filename='artberry.ico') }}" type="image/x-icon"> <link rel="icon" href="{{ url_for('static', filename='artberry.ico') }}" type="image/x-icon">
<title>🫐comic edit - artberry🫐</title> <title>🫐comic edit - artberry🫐</title>
</head> </head>
<body> <body>
@ -26,12 +25,12 @@
<ul> <ul>
{% for page in comic_pages %} {% for page in comic_pages %}
<li> <li>
<img src="{{ url_for('static', filename='comics/' + comic.name + '/' + page) }}" alt="Comic Page {{ loop.index }}"> <img src="{{ url_for('static', filename='comics/' + comic.name + '/' + page.file_path) }}" alt="Comic Page {{ loop.index }}">
<h3>Page {{ loop.index }}</h3> <h3>Page {{ loop.index }}</h3>
<div class="form-group"> <div class="form-group">
<form method="POST" action="{{ url_for('comic_edit', comic_id=comic.id) }}" class="form-group"> <form method="POST" action="{{ url_for('comic_edit', comic_id=comic.id) }}" class="form-group">
{{ form.hidden_tag() }} {{ form.hidden_tag() }}
<input type="hidden" name="page" value="{{ page }}"> <input type="hidden" name="page" value="{{ page.id }}">
<button type="submit" name="action" value="delete">Delete</button> <button type="submit" name="action" value="delete">Delete</button>
</form> </form>
</div> </div>
@ -40,6 +39,7 @@
{{ form.hidden_tag() }} {{ form.hidden_tag() }}
<label for="new_page_update">Replace with:</label> <label for="new_page_update">Replace with:</label>
<input type="file" name="new_page" accept="image/*" required class="file-input"> <input type="file" name="new_page" accept="image/*" required class="file-input">
<input type="hidden" name="page" value="{{ page.id }}">
<button type="submit" name="action" value="update">Replace</button> <button type="submit" name="action" value="update">Replace</button>
</form> </form>
</div> </div>

View File

@ -7,7 +7,6 @@
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}"> <link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/upload_video.css') }}"> <link rel="stylesheet" href="{{ url_for('static', filename='css/upload_video.css') }}">
<link rel="icon" href="{{ url_for('static', filename='artberry.ico') }}" type="image/x-icon"> <link rel="icon" href="{{ url_for('static', filename='artberry.ico') }}" type="image/x-icon">
<link href="https://fonts.googleapis.com/css2?family=Comfortaa:wght@300&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Comfortaa:wght@300&display=swap" rel="stylesheet">
<script src="https://www.google.com/recaptcha/api.js" async defer></script> <script src="https://www.google.com/recaptcha/api.js" async defer></script>
</head> </head>