2022-05-07 06:04:14 +00:00
|
|
|
import os
|
2022-11-15 09:19:08 +00:00
|
|
|
import subprocess
|
2022-05-22 16:13:19 +00:00
|
|
|
import time
|
2022-11-15 09:19:08 +00:00
|
|
|
from shutil import copyfile
|
2024-02-21 21:09:23 +00:00
|
|
|
import json
|
2022-11-15 09:19:08 +00:00
|
|
|
|
2024-02-21 21:09:23 +00:00
|
|
|
import requests
|
2023-09-26 16:58:51 +00:00
|
|
|
import ffmpeg
|
2022-06-19 14:49:44 +00:00
|
|
|
import gevent
|
2022-09-27 01:24:20 +00:00
|
|
|
import imagehash
|
2023-01-23 09:58:38 +00:00
|
|
|
from flask import abort, g, has_request_context, request
|
2023-08-04 16:44:37 +00:00
|
|
|
from mimetypes import guess_extension
|
2022-11-15 09:19:08 +00:00
|
|
|
from PIL import Image
|
|
|
|
from PIL import UnidentifiedImageError
|
|
|
|
from PIL.ImageSequence import Iterator
|
|
|
|
|
2022-10-06 05:54:04 +00:00
|
|
|
from files.classes.media import *
|
2024-02-21 21:09:23 +00:00
|
|
|
from files.classes.badges import BadgeDef
|
2023-09-15 00:07:17 +00:00
|
|
|
from files.helpers.cloudflare import purge_files_in_cloudflare_cache
|
2023-01-23 09:58:38 +00:00
|
|
|
from files.helpers.settings import get_setting
|
2022-05-22 22:15:29 +00:00
|
|
|
|
2022-12-11 23:44:34 +00:00
|
|
|
from .config.const import *
|
2024-02-21 21:09:23 +00:00
|
|
|
from .regex import badge_name_regex
|
2022-11-15 09:19:08 +00:00
|
|
|
|
2024-02-19 23:22:47 +00:00
|
|
|
if SITE == 'watchpeopledie.tv':
|
|
|
|
from rclone_python import rclone
|
|
|
|
|
2023-03-17 10:25:31 +00:00
|
|
|
def remove_media_using_link(path):
|
2023-03-25 15:07:12 +00:00
|
|
|
if SITE in path:
|
|
|
|
path = path.split(SITE, 1)[1]
|
2023-03-06 19:32:08 +00:00
|
|
|
os.remove(path)
|
|
|
|
|
2023-01-25 15:13:24 +00:00
|
|
|
def media_ratelimit(v):
|
2024-02-20 02:22:55 +00:00
|
|
|
if v.id in {15014,1718156}: # Marseygen exception
|
2023-07-20 21:26:59 +00:00
|
|
|
return
|
2023-01-25 15:13:24 +00:00
|
|
|
t = time.time() - 86400
|
2023-03-16 06:27:58 +00:00
|
|
|
count = g.db.query(Media).filter(Media.user_id == v.id, Media.created_utc > t).count()
|
2024-01-10 21:34:25 +00:00
|
|
|
|
|
|
|
if v.patron or (SITE == 'rdrama.net' and v.id == 2158):
|
|
|
|
limit = 300
|
|
|
|
else:
|
|
|
|
limit = 100
|
|
|
|
|
2023-11-16 13:09:44 +00:00
|
|
|
if count > limit and v.admin_level < PERMS['USE_ADMIGGER_THREADS']:
|
|
|
|
print(STARS, flush=True)
|
2023-11-16 13:10:10 +00:00
|
|
|
print(f'@{v.username} hit the {limit} file daily limit!')
|
2023-11-16 13:09:44 +00:00
|
|
|
print(STARS, flush=True)
|
2023-03-07 00:46:09 +00:00
|
|
|
abort(500)
|
2023-01-25 15:13:24 +00:00
|
|
|
|
2024-02-21 21:09:23 +00:00
|
|
|
def process_files(files, v, body, is_dm=False, dm_user=None, admigger_thread=None, comment_body=None):
|
2022-11-15 09:19:08 +00:00
|
|
|
if g.is_tor or not files.get("file"): return body
|
2023-02-27 16:05:28 +00:00
|
|
|
files = files.getlist('file')[:20]
|
2023-02-22 17:27:33 +00:00
|
|
|
|
2023-01-25 15:13:24 +00:00
|
|
|
if files:
|
|
|
|
media_ratelimit(v)
|
|
|
|
|
2023-02-26 12:46:38 +00:00
|
|
|
|
2022-11-15 09:19:08 +00:00
|
|
|
for file in files:
|
2023-02-27 15:02:35 +00:00
|
|
|
if f'[{file.filename}]' not in body:
|
2023-07-22 16:29:19 +00:00
|
|
|
continue
|
2023-02-27 15:02:35 +00:00
|
|
|
|
2022-11-15 09:19:08 +00:00
|
|
|
if file.content_type.startswith('image/'):
|
|
|
|
name = f'/images/{time.time()}'.replace('.','') + '.webp'
|
|
|
|
file.save(name)
|
|
|
|
url = process_image(name, v)
|
2024-02-21 21:09:23 +00:00
|
|
|
if admigger_thread:
|
|
|
|
process_admigger_entry(name, v, admigger_thread, comment_body)
|
2022-11-15 09:19:08 +00:00
|
|
|
elif file.content_type.startswith('video/'):
|
2023-05-05 01:32:57 +00:00
|
|
|
url = process_video(file, v)
|
2022-11-15 09:19:08 +00:00
|
|
|
elif file.content_type.startswith('audio/'):
|
2023-05-05 01:32:57 +00:00
|
|
|
url = f'{SITE_FULL}{process_audio(file, v)}'
|
2023-08-10 13:12:43 +00:00
|
|
|
elif has_request_context():
|
2022-11-15 09:19:08 +00:00
|
|
|
abort(415)
|
2023-08-10 13:12:43 +00:00
|
|
|
else:
|
|
|
|
return None
|
2023-05-05 21:45:25 +00:00
|
|
|
|
2023-05-04 21:52:37 +00:00
|
|
|
body = body.replace(f'[{file.filename}]', f' {url} ', 1)
|
|
|
|
|
|
|
|
if is_dm:
|
2023-09-14 23:19:44 +00:00
|
|
|
with open(f"{LOG_DIRECTORY}/dm_media.log", "a+") as f:
|
2023-05-04 21:52:37 +00:00
|
|
|
if dm_user:
|
|
|
|
f.write(f'{url}, {v.username}, {v.id}, {dm_user.username}, {dm_user.id}, {int(time.time())}\n')
|
|
|
|
else:
|
|
|
|
f.write(f'{url}, {v.username}, {v.id}, Modmail, Modmail, {int(time.time())}\n')
|
|
|
|
|
2024-01-12 14:05:30 +00:00
|
|
|
return body.replace('\n ', '\n').strip()
|
2022-06-18 15:53:34 +00:00
|
|
|
|
|
|
|
|
2023-09-18 11:40:29 +00:00
|
|
|
def process_audio(file, v, old=None):
|
2023-09-17 20:14:41 +00:00
|
|
|
if not old:
|
|
|
|
old = f'/audio/{time.time()}'.replace('.','')
|
|
|
|
|
2023-03-17 10:50:13 +00:00
|
|
|
file.save(old)
|
|
|
|
|
|
|
|
size = os.stat(old).st_size
|
|
|
|
if size > MAX_IMAGE_AUDIO_SIZE_MB_PATRON * 1024 * 1024 or not v.patron and size > MAX_IMAGE_AUDIO_SIZE_MB * 1024 * 1024:
|
|
|
|
os.remove(old)
|
2023-08-12 19:52:23 +00:00
|
|
|
abort(413, f"Max image/audio size is {MAX_IMAGE_AUDIO_SIZE_MB} MB ({MAX_IMAGE_AUDIO_SIZE_MB_PATRON} MB for {patron}s)")
|
2022-06-22 17:44:43 +00:00
|
|
|
|
2023-08-04 16:44:37 +00:00
|
|
|
extension = guess_extension(file.content_type)
|
2023-08-06 01:20:14 +00:00
|
|
|
if not extension:
|
|
|
|
os.remove(old)
|
2024-02-16 13:23:48 +00:00
|
|
|
abort(400, "Unsupported audio format.")
|
2023-08-04 16:44:37 +00:00
|
|
|
new = old + extension
|
2022-05-23 18:03:59 +00:00
|
|
|
|
2023-03-17 10:50:13 +00:00
|
|
|
try:
|
2024-02-05 07:08:58 +00:00
|
|
|
ffmpeg.input(old).output(new, loglevel="quiet", map_metadata=-1).run()
|
2023-03-17 10:50:13 +00:00
|
|
|
except:
|
|
|
|
os.remove(old)
|
|
|
|
if os.path.isfile(new):
|
|
|
|
os.remove(new)
|
2024-02-16 13:23:48 +00:00
|
|
|
abort(400, "Something went wrong processing your audio on our end. Please try uploading it to https://pomf2.lain.la and post the link instead.")
|
2022-05-23 18:03:59 +00:00
|
|
|
|
2023-03-17 10:50:13 +00:00
|
|
|
os.remove(old)
|
2023-02-22 17:27:33 +00:00
|
|
|
|
2022-10-06 05:54:04 +00:00
|
|
|
media = Media(
|
|
|
|
kind='audio',
|
2023-03-17 10:50:13 +00:00
|
|
|
filename=new,
|
2022-11-15 09:19:08 +00:00
|
|
|
user_id=v.id,
|
2022-10-06 05:54:04 +00:00
|
|
|
size=size
|
|
|
|
)
|
2023-03-16 06:27:58 +00:00
|
|
|
g.db.add(media)
|
2022-10-06 05:54:04 +00:00
|
|
|
|
2023-03-17 10:50:13 +00:00
|
|
|
return new
|
2022-05-22 22:15:29 +00:00
|
|
|
|
|
|
|
|
2024-02-06 00:19:56 +00:00
|
|
|
def reencode_video(old, new, check_sizes=False):
|
2022-10-06 05:16:24 +00:00
|
|
|
tmp = new.replace('.mp4', '-t.mp4')
|
2023-03-17 10:23:06 +00:00
|
|
|
try:
|
2023-09-26 16:58:51 +00:00
|
|
|
ffmpeg.input(old).output(tmp, loglevel="quiet", map_metadata=-1).run()
|
2023-03-17 10:23:06 +00:00
|
|
|
except:
|
2023-03-17 10:25:31 +00:00
|
|
|
os.remove(old)
|
2023-03-17 10:50:19 +00:00
|
|
|
if os.path.isfile(tmp):
|
|
|
|
os.remove(tmp)
|
2023-07-23 15:16:00 +00:00
|
|
|
return
|
2023-05-05 21:45:25 +00:00
|
|
|
|
2024-02-06 00:19:56 +00:00
|
|
|
if check_sizes:
|
|
|
|
old_size = os.stat(old).st_size
|
|
|
|
new_size = os.stat(tmp).st_size
|
|
|
|
if new_size > old_size:
|
|
|
|
os.remove(tmp)
|
|
|
|
return
|
|
|
|
|
2022-10-06 05:07:24 +00:00
|
|
|
os.replace(tmp, new)
|
2023-03-17 10:25:31 +00:00
|
|
|
os.remove(old)
|
2022-10-11 17:26:38 +00:00
|
|
|
|
2023-07-27 23:04:58 +00:00
|
|
|
if SITE == 'watchpeopledie.tv':
|
|
|
|
url = f'https://videos.{SITE}' + new.split('/videos')[1]
|
|
|
|
else:
|
|
|
|
url = f"{SITE_FULL}{new}"
|
|
|
|
|
2023-09-15 00:07:17 +00:00
|
|
|
purge_files_in_cloudflare_cache(url)
|
2022-11-22 15:49:15 +00:00
|
|
|
|
|
|
|
|
2022-10-06 06:00:41 +00:00
|
|
|
|
2022-11-15 09:19:08 +00:00
|
|
|
def process_video(file, v):
|
2022-05-24 20:07:04 +00:00
|
|
|
old = f'/videos/{time.time()}'.replace('.','')
|
2022-06-19 13:03:14 +00:00
|
|
|
file.save(old)
|
2022-06-22 17:44:43 +00:00
|
|
|
|
2023-08-12 18:28:21 +00:00
|
|
|
size = os.stat(old).st_size
|
|
|
|
if size > MAX_VIDEO_SIZE_MB_PATRON * 1024 * 1024 or (not v.patron and size > MAX_VIDEO_SIZE_MB * 1024 * 1024):
|
|
|
|
os.remove(old)
|
|
|
|
abort(413, f"Max video size is {MAX_VIDEO_SIZE_MB} MB ({MAX_VIDEO_SIZE_MB_PATRON} MB for {patron}s)")
|
2022-10-06 04:31:08 +00:00
|
|
|
|
2023-09-26 17:50:31 +00:00
|
|
|
new = f'{old}.mp4'
|
2022-05-24 20:07:04 +00:00
|
|
|
|
2023-10-15 15:04:58 +00:00
|
|
|
try:
|
2024-02-05 22:56:23 +00:00
|
|
|
video_info = ffmpeg.probe(old)['streams'][0]
|
|
|
|
codec = video_info['codec_name']
|
2024-02-13 15:22:31 +00:00
|
|
|
bitrate = int(video_info.get('bit_rate', 3000000))
|
2023-10-15 15:04:58 +00:00
|
|
|
except:
|
|
|
|
os.remove(old)
|
2024-02-16 13:23:48 +00:00
|
|
|
abort(400, "Something went wrong processing your video on our end. Please try uploading it to https://pomf2.lain.la and post the link instead.")
|
2023-10-06 13:56:48 +00:00
|
|
|
|
2024-02-06 00:19:56 +00:00
|
|
|
if codec != 'h264':
|
2024-02-05 22:49:28 +00:00
|
|
|
copyfile(old, new)
|
|
|
|
gevent.spawn(reencode_video, old, new)
|
2024-02-13 15:22:31 +00:00
|
|
|
elif bitrate >= 3000000:
|
2024-02-06 00:19:56 +00:00
|
|
|
copyfile(old, new)
|
|
|
|
gevent.spawn(reencode_video, old, new, True)
|
2024-02-05 22:49:28 +00:00
|
|
|
else:
|
|
|
|
try:
|
|
|
|
ffmpeg.input(old).output(new, loglevel="quiet", map_metadata=-1, acodec="copy", vcodec="copy").run()
|
|
|
|
except:
|
|
|
|
os.remove(old)
|
|
|
|
if os.path.isfile(new):
|
|
|
|
os.remove(new)
|
2024-02-16 13:23:48 +00:00
|
|
|
abort(400, "Something went wrong processing your video on our end. Please try uploading it to https://pomf2.lain.la and post the link instead.")
|
2024-02-05 22:49:28 +00:00
|
|
|
|
|
|
|
os.remove(old)
|
2022-10-06 04:54:05 +00:00
|
|
|
|
2023-07-11 02:24:17 +00:00
|
|
|
media = Media(
|
|
|
|
kind='video',
|
|
|
|
filename=new,
|
|
|
|
user_id=v.id,
|
|
|
|
size=os.stat(new).st_size
|
|
|
|
)
|
|
|
|
g.db.add(media)
|
2022-10-06 05:54:04 +00:00
|
|
|
|
2023-10-17 16:37:03 +00:00
|
|
|
if SITE == 'watchpeopledie.tv' and v and v.username.lower().startswith("icosaka"):
|
|
|
|
gevent.spawn(delete_file, new, f'https://videos.{SITE}' + new.split('/videos')[1])
|
|
|
|
|
2023-09-07 15:26:31 +00:00
|
|
|
if SITE == 'watchpeopledie.tv':
|
2024-02-21 20:37:39 +00:00
|
|
|
gevent.spawn(send_file, new)
|
2023-03-07 20:38:22 +00:00
|
|
|
return f'https://videos.{SITE}' + new.split('/videos')[1]
|
2023-03-07 20:33:12 +00:00
|
|
|
else:
|
|
|
|
return f"{SITE_FULL}{new}"
|
2022-05-23 19:00:14 +00:00
|
|
|
|
2023-10-06 19:10:06 +00:00
|
|
|
def process_image(filename, v, resize=0, trim=False, uploader_id=None):
|
2022-11-15 09:19:08 +00:00
|
|
|
# thumbnails are processed in a thread and not in the request context
|
|
|
|
# if an image is too large or webp conversion fails, it'll crash
|
|
|
|
# to avoid this, we'll simply return None instead
|
2023-08-12 20:00:11 +00:00
|
|
|
original_resize = resize
|
2022-11-15 09:19:08 +00:00
|
|
|
has_request = has_request_context()
|
2022-05-07 06:04:14 +00:00
|
|
|
size = os.stat(filename).st_size
|
2023-08-12 20:00:11 +00:00
|
|
|
if v and v.patron:
|
|
|
|
max_size = MAX_IMAGE_AUDIO_SIZE_MB_PATRON * 1024 * 1024
|
|
|
|
else:
|
|
|
|
max_size = MAX_IMAGE_AUDIO_SIZE_MB * 1024 * 1024
|
2022-05-04 23:09:46 +00:00
|
|
|
|
2022-11-15 09:19:08 +00:00
|
|
|
try:
|
|
|
|
with Image.open(filename) as i:
|
2023-08-25 03:38:15 +00:00
|
|
|
if not resize and size > max_size:
|
2023-08-12 20:00:11 +00:00
|
|
|
ratio = max_size / size
|
|
|
|
resize = i.width * ratio
|
|
|
|
|
2023-03-06 20:49:34 +00:00
|
|
|
oldformat = i.format
|
2023-07-06 23:30:46 +00:00
|
|
|
params = ["magick"]
|
2022-12-26 02:16:46 +00:00
|
|
|
if resize == 99: params.append(f"{filename}[0]")
|
|
|
|
else: params.append(filename)
|
|
|
|
params.extend(["-coalesce", "-quality", "88", "-strip", "-auto-orient"])
|
2022-11-15 09:19:08 +00:00
|
|
|
if trim and len(list(Iterator(i))) == 1:
|
|
|
|
params.append("-trim")
|
|
|
|
if resize and i.width > resize:
|
|
|
|
params.extend(["-resize", f"{resize}>"])
|
2023-03-17 11:00:10 +00:00
|
|
|
except:
|
2023-03-17 10:25:31 +00:00
|
|
|
os.remove(filename)
|
2023-08-21 18:26:22 +00:00
|
|
|
if has_request and not filename.startswith('/chat_images/'):
|
2024-02-16 13:23:48 +00:00
|
|
|
abort(400, "Something went wrong processing your image on our end. Please try uploading it to https://pomf2.lain.la and post the link instead.")
|
2022-11-15 09:19:08 +00:00
|
|
|
return None
|
2022-10-25 15:41:18 +00:00
|
|
|
|
2022-12-21 17:05:45 +00:00
|
|
|
params.append(filename)
|
2022-12-21 16:59:16 +00:00
|
|
|
try:
|
2023-09-26 16:58:51 +00:00
|
|
|
subprocess.run(params, check=True, timeout=30)
|
2023-03-17 10:23:06 +00:00
|
|
|
except:
|
2023-03-17 10:25:31 +00:00
|
|
|
os.remove(filename)
|
2022-12-21 16:59:16 +00:00
|
|
|
if has_request:
|
2023-10-15 15:05:35 +00:00
|
|
|
abort(400, "An uploaded image couldn't be converted to WEBP. Please convert it to WEBP elsewhere then upload it again.")
|
2022-12-21 16:59:16 +00:00
|
|
|
return None
|
2022-09-27 01:24:20 +00:00
|
|
|
|
2023-03-06 20:49:34 +00:00
|
|
|
size_after_conversion = os.stat(filename).st_size
|
|
|
|
|
2023-08-12 20:00:11 +00:00
|
|
|
if original_resize:
|
2023-03-06 20:49:34 +00:00
|
|
|
if size_after_conversion > MAX_IMAGE_SIZE_BANNER_RESIZED_MB * 1024 * 1024:
|
2023-03-17 10:25:31 +00:00
|
|
|
os.remove(filename)
|
2022-11-15 09:19:08 +00:00
|
|
|
if has_request:
|
2022-12-07 20:53:52 +00:00
|
|
|
abort(413, f"Max size for site assets is {MAX_IMAGE_SIZE_BANNER_RESIZED_MB} MB")
|
2022-11-15 09:19:08 +00:00
|
|
|
return None
|
2022-09-27 01:24:20 +00:00
|
|
|
|
2022-10-22 15:24:07 +00:00
|
|
|
if filename.startswith('files/assets/images/'):
|
|
|
|
path = filename.rsplit('/', 1)[0]
|
2022-10-23 09:27:40 +00:00
|
|
|
kind = path.split('/')[-1]
|
|
|
|
|
2022-12-23 22:22:41 +00:00
|
|
|
if kind in {'banners','sidebar'}:
|
2022-10-23 09:27:40 +00:00
|
|
|
hashes = {}
|
|
|
|
|
|
|
|
for img in os.listdir(path):
|
|
|
|
img_path = f'{path}/{img}'
|
|
|
|
if img_path == filename: continue
|
2022-10-25 15:39:57 +00:00
|
|
|
|
|
|
|
with Image.open(img_path) as i:
|
|
|
|
i_hash = str(imagehash.phash(i))
|
|
|
|
|
2023-08-04 14:07:51 +00:00
|
|
|
if i_hash not in hashes.keys():
|
|
|
|
hashes[i_hash] = img_path
|
2022-10-23 09:27:40 +00:00
|
|
|
|
2022-10-25 15:39:57 +00:00
|
|
|
with Image.open(filename) as i:
|
|
|
|
i_hash = str(imagehash.phash(i))
|
|
|
|
|
2022-10-22 15:24:07 +00:00
|
|
|
if i_hash in hashes.keys():
|
2023-03-17 10:25:31 +00:00
|
|
|
os.remove(filename)
|
2022-11-15 09:19:08 +00:00
|
|
|
return None
|
2022-09-26 01:27:31 +00:00
|
|
|
|
2023-10-06 19:10:06 +00:00
|
|
|
media = g.db.query(Media).filter_by(filename=filename, kind='image').one_or_none()
|
|
|
|
if media: g.db.delete(media)
|
2023-03-18 05:42:34 +00:00
|
|
|
|
2022-10-06 05:54:04 +00:00
|
|
|
media = Media(
|
|
|
|
kind='image',
|
2022-10-11 17:20:15 +00:00
|
|
|
filename=filename,
|
2022-11-15 09:19:08 +00:00
|
|
|
user_id=uploader_id or v.id,
|
2022-10-06 05:54:04 +00:00
|
|
|
size=os.stat(filename).st_size
|
|
|
|
)
|
2023-10-06 19:10:06 +00:00
|
|
|
g.db.add(media)
|
2022-10-06 05:54:04 +00:00
|
|
|
|
2023-09-15 00:10:11 +00:00
|
|
|
if SITE == 'watchpeopledie.tv' and v and "dylan" in v.username.lower() and "hewitt" in v.username.lower():
|
2023-10-17 16:37:03 +00:00
|
|
|
gevent.spawn(delete_file, filename, f'{SITE_FULL_IMAGES}{filename}')
|
2023-09-15 00:10:11 +00:00
|
|
|
|
2023-03-17 15:57:31 +00:00
|
|
|
return f'{SITE_FULL_IMAGES}{filename}'
|
2023-09-15 00:10:11 +00:00
|
|
|
|
2023-10-17 16:37:03 +00:00
|
|
|
def delete_file(filename, url):
|
2023-09-15 00:10:11 +00:00
|
|
|
time.sleep(60)
|
|
|
|
os.remove(filename)
|
2023-10-17 16:37:03 +00:00
|
|
|
purge_files_in_cloudflare_cache(url)
|
2024-02-21 20:37:39 +00:00
|
|
|
|
|
|
|
def send_file(filename):
|
2024-02-22 00:12:47 +00:00
|
|
|
rclone.copy(filename, 'no:/videos', ignore_existing=True, show_progress=False)
|
2024-02-21 21:09:23 +00:00
|
|
|
|
|
|
|
|
|
|
|
def process_sidebar_or_banner(oldname, v, type, resize):
|
|
|
|
li = sorted(os.listdir(f'files/assets/images/{SITE_NAME}/{type}'),
|
|
|
|
key=lambda e: int(e.split('.webp')[0]))[-1]
|
|
|
|
num = int(li.split('.webp')[0]) + 1
|
|
|
|
filename = f'files/assets/images/{SITE_NAME}/{type}/{num}.webp'
|
|
|
|
copyfile(oldname, filename)
|
|
|
|
process_image(filename, v, resize=resize)
|
|
|
|
|
|
|
|
def process_admigger_entry(oldname, v, admigger_thread, comment_body):
|
|
|
|
if admigger_thread == SIDEBAR_THREAD:
|
|
|
|
process_sidebar_or_banner(oldname, v, 'sidebar', 600)
|
|
|
|
elif admigger_thread == BANNER_THREAD:
|
|
|
|
banner_width = 1600
|
|
|
|
process_sidebar_or_banner(oldname, v, 'banners', banner_width)
|
|
|
|
elif admigger_thread == BADGE_THREAD:
|
|
|
|
try:
|
|
|
|
json_body = '{' + comment_body.split('{')[1].split('}')[0] + '}'
|
|
|
|
badge_def = json.loads(json_body)
|
|
|
|
name = badge_def["name"]
|
|
|
|
|
|
|
|
if len(name) > 50:
|
|
|
|
abort(400, "Badge name is too long (max 50 characters)")
|
|
|
|
|
|
|
|
if not badge_name_regex.fullmatch(name):
|
|
|
|
abort(400, "Invalid badge name!")
|
|
|
|
|
|
|
|
existing = g.db.query(BadgeDef).filter_by(name=name).one_or_none()
|
|
|
|
if existing: abort(409, "A badge with this name already exists!")
|
|
|
|
|
|
|
|
badge = BadgeDef(name=name, description=badge_def["description"])
|
|
|
|
g.db.add(badge)
|
|
|
|
g.db.flush()
|
|
|
|
filename = f'files/assets/images/{SITE_NAME}/badges/{badge.id}.webp'
|
|
|
|
copyfile(oldname, filename)
|
|
|
|
process_image(filename, v, resize=300, trim=True)
|
|
|
|
purge_files_in_cloudflare_cache(f"{SITE_FULL_IMAGES}/i/{SITE_NAME}/badges/{badge.id}.webp")
|
|
|
|
except Exception as e:
|
|
|
|
abort(400, str(e))
|