Remove Thumbnails table

Daddy PyLint not happy with me
This commit is contained in:
Michał 2023-03-26 23:34:03 +00:00
parent db20ce7919
commit 3331edf24d
7 changed files with 104 additions and 144 deletions

View file

@ -69,14 +69,13 @@ def create_app(test_config=None):
# Error handlers
@app.errorhandler(Exception)
def error_page(err):
# If the error is a HTTP error, return the error page
if isinstance(err, HTTPException):
error = err.code
msg = err.description
return render_template('error.html', error=error, msg=msg), err.code
# If the error is not an HTTPException, return a 500 error
if not isinstance(err, HTTPException):
abort(500)
# Otherwise this an internal error
abort(500)
error = err.code
msg = err.description
return render_template('error.html', error=error, msg=msg), err.code
# Load login, registration and logout manager
from gallery import auth

View file

@ -60,20 +60,6 @@ class Posts (base): # pylint: disable=too-few-public-methods, C0103
post_alt = Column(String, nullable=False)
junction = relationship('GroupJunction', backref='posts')
thumbnail = relationship('Thumbnails', backref='posts')
class Thumbnails (base): # pylint: disable=too-few-public-methods, C0103
"""
Thumbnail table
"""
__tablename__ = 'thumbnails'
id = Column(Integer, primary_key=True)
file_name = Column(String, unique=True, nullable=False)
file_ext = Column(String, nullable=False)
resolution = Column(PickleType, nullable=False)
post_id = Column(Integer, ForeignKey('posts.id'))
class Groups (base): # pylint: disable=too-few-public-methods, C0103

View file

@ -4,9 +4,9 @@ Onlylegs - API endpoints
from uuid import uuid4
import os
import pathlib
import platformdirs
import logging
from datetime import datetime as dt
import platformdirs
from flask import Blueprint, send_from_directory, abort, flash, jsonify, request, g, current_app
from werkzeug.utils import secure_filename
@ -18,7 +18,7 @@ from gallery.auth import login_required
from gallery import db
from gallery.utils import metadata as mt
from gallery.utils.generate_image import ImageGenerator
from gallery.utils.generate_image import generate_thumbnail
blueprint = Blueprint('api', __name__, url_prefix='/api')
@ -41,12 +41,12 @@ def file(file_name):
abort(404)
return send_from_directory(current_app.config['UPLOAD_FOLDER'], file_name)
thumb = ImageGenerator.thumbnail(file_name, res)
thumb = generate_thumbnail(file_name, res)
if not thumb:
abort(404)
return send_from_directory(os.path.dirname(thumb), os.path.basename(thumb))
@ -126,8 +126,8 @@ def delete_image(image_id):
# Delete cached files
cache_path = os.path.join(platformdirs.user_config_dir('onlylegs'), 'cache')
cache_name = img.file_name.rsplit('.')[0]
for file in pathlib.Path(cache_path).glob(cache_name + '*'):
os.remove(file)
for cache_file in pathlib.Path(cache_path).glob(cache_name + '*'):
os.remove(cache_file)
# Delete from database
db_session.query(db.Posts).filter_by(id=image_id).delete()
@ -209,40 +209,3 @@ def metadata(img_id):
exif = mt.Metadata(img_path).yoink()
return jsonify(exif)
@blueprint.route('/logfile')
@login_required
def logfile():
"""
Gets the log file and returns it as a JSON object
"""
log_dict = {}
with open('only.log', encoding='utf-8', mode='r') as file:
for i, line in enumerate(file):
line = line.split(' : ')
event = line[0].strip().split(' ')
event_data = {
'date': event[0],
'time': event[1],
'severity': event[2],
'owner': event[3]
}
message = line[1].strip()
try:
message_data = {
'code': int(message[1:4]),
'message': message[5:].strip()
}
except ValueError:
message_data = {'code': 0, 'message': message}
except Exception as err:
logging.error('Could not parse log file: %s', err)
abort(500)
log_dict[i] = {'event': event_data, 'message': message_data}
return jsonify(log_dict)

View file

@ -60,13 +60,18 @@ def group(group_id):
for image in group_images:
image = db_session.query(db.Posts).filter(db.Posts.id == image[0]).first()
images.append(image)
if images:
text_colour = contrast.contrast(images[0].image_colours[0], 'rgb(var(--fg-black))', 'rgb(var(--fg-white))')
text_colour = contrast.contrast(images[0].image_colours[0],
'rgb(var(--fg-black))',
'rgb(var(--fg-white))')
else:
text_colour = 'rgb(var(--fg-black))'
return render_template('groups/group.html', group=group_item, images=images, text_colour=text_colour)
return render_template('groups/group.html',
group=group_item,
images=images,
text_colour=text_colour)
@blueprint.route('/<int:group_id>/<int:image_id>')

View file

@ -6,10 +6,10 @@
top: 0
left: 0
background-color: RGB($fg-white)
// background-image: linear-gradient(to right, RGB($bg-200) 15%, RGB($bg-400) 35%, RGB($bg-200) 50%)
// background-size: 1000px 640px
// animation: imgLoading 1.8s linear infinite forwards
background-color: RGB($bg-300)
background-image: linear-gradient(to right, RGB($bg-400) 15%, RGB($bg-200) 35%, RGB($bg-400) 50%)
background-size: 1000px 640px
animation: imgLoading 1.8s linear infinite forwards
user-select: none
overflow: hidden

View file

@ -1,18 +1,22 @@
"""
Calculate the contrast between two colors
"""
def contrast(background, light, dark, threshold = 0.179):
"""
Calculate the contrast between two colors
background: tuple of (r, g, b) values
light: color to use if the background is light
dark: color to use if the background is dark
threshold: the threshold to use for determining lightness, the default is w3 recommended
"""
r = background[0]
g = background[1]
b = background[2]
red = background[0]
green = background[1]
blue = background[2]
# Calculate contrast
uicolors = [r / 255, g / 255, b / 255]
c = [col / 12.92 if col <= 0.03928 else ((col + 0.055) / 1.055) ** 2.4 for col in uicolors]
l = (0.2126 * c[0]) + (0.7152 * c[1]) + (0.0722 * c[2])
return light if l > threshold else dark
uicolors = [red / 255, green / 255, blue / 255]
cont = [col / 12.92 if col <= 0.03928 else ((col + 0.055) / 1.055) ** 2.4 for col in uicolors]
lightness = (0.2126 * cont[0]) + (0.7152 * cont[1]) + (0.0722 * cont[2])
return light if lightness > threshold else dark

View file

@ -1,3 +1,7 @@
"""
Tools for generating images and thumbnails
"""
import os
import platformdirs
from PIL import Image, ImageOps #, ImageFilter
@ -8,67 +12,66 @@ CACHE_PATH = platformdirs.user_config_dir('onlylegs') + '/cache'
UPLOAD_PATH = platformdirs.user_config_dir('onlylegs') + '/uploads'
class ImageGenerator:
def thumbnail(name, resolution, ext=None):
"""
Image thumbnail generator
Uses PIL to generate a thumbnail of the image and saves it to the cache directory
Name is the filename
resolution: 400x400 or thumb, or any other resolution
ext is the file extension of the image
"""
# Make image cache directory if it doesn't exist
if not os.path.exists(CACHE_PATH):
os.makedirs(CACHE_PATH)
def generate_thumbnail(file_name, resolution, ext=None):
"""
Image thumbnail generator
Uses PIL to generate a thumbnail of the image and saves it to the cache directory
Name is the filename
resolution: 400x400 or thumb, or any other resolution
ext is the file extension of the image
"""
# Make image cache directory if it doesn't exist
if not os.path.exists(CACHE_PATH):
os.makedirs(CACHE_PATH)
# no sussy business
name, name_ext = secure_filename(name).rsplit('.')
if not ext:
ext = name_ext.strip('.')
# PIL doesnt like jpg so we convert it to jpeg
if ext.lower() == "jpg":
ext = "jpeg"
# Set resolution based on preset resolutions
if resolution in ['thumb', 'thumbnail']:
res_x, res_y = (400, 400)
elif resolution in ['prev', 'preview']:
res_x, res_y = (1920, 1080)
elif len(resolution.split('x')) == 2:
res_x, res_y = resolution.split('x')
else:
return None
# If image has been already generated, return it from the cache
if os.path.exists(os.path.join(CACHE_PATH, f'{name}_{res_x}x{res_y}.{ext}')):
return os.path.join(CACHE_PATH, f'{name}_{res_x}x{res_y}.{ext}')
# Check if image exists in the uploads directory
if not os.path.exists(os.path.join(UPLOAD_PATH, f'{name}.{name_ext}')):
return None
# Open image and rotate it based on EXIF data and get ICC profile so colors are correct
image = Image.open(os.path.join(UPLOAD_PATH, f'{name}.{name_ext}'))
image_icc = image.info.get("icc_profile")
img_x, img_y = image.size
# Resize image to fit the resolution
image = ImageOps.exif_transpose(image)
image.thumbnail((min(img_x, int(res_x)), min(img_y, int(res_y))), Image.ANTIALIAS)
# no sussy business
file_name, file_ext = secure_filename(file_name).rsplit('.')
if not ext:
ext = file_ext.strip('.')
# Save image to cache directory
try:
image.save(os.path.join(CACHE_PATH,f'{name}_{res_x}x{res_y}.{ext}'),
icc_profile=image_icc)
except OSError:
# This usually happens when saving a JPEG with an ICC profile,
# so we convert to RGB and try again
image = image.convert('RGB')
image.save(os.path.join(CACHE_PATH, f'{name}_{res_x}x{res_y}.{ext}'),
icc_profile=image_icc)
# No need to keep the image in memory, learned the hard way
image.close()
return os.path.join(CACHE_PATH, f'{name}_{res_x}x{res_y}.{ext}')
# PIL doesnt like jpg so we convert it to jpeg
if ext.lower() == "jpg":
ext = "jpeg"
# Set resolution based on preset resolutions
if resolution in ['thumb', 'thumbnail']:
res_x, res_y = (400, 400)
elif resolution in ['prev', 'preview']:
res_x, res_y = (1920, 1080)
elif len(resolution.split('x')) == 2:
res_x, res_y = resolution.split('x')
else:
return None
# If image has been already generated, return it from the cache
if os.path.exists(os.path.join(CACHE_PATH, f'{file_name}_{res_x}x{res_y}.{ext}')):
return os.path.join(CACHE_PATH, f'{file_name}_{res_x}x{res_y}.{ext}')
# Check if image exists in the uploads directory
if not os.path.exists(os.path.join(UPLOAD_PATH, f'{file_name}.{file_ext}')):
return None
# Open image and rotate it based on EXIF data and get ICC profile so colors are correct
image = Image.open(os.path.join(UPLOAD_PATH, f'{file_name}.{file_ext}'))
image_icc = image.info.get("icc_profile")
img_x, img_y = image.size
# Resize image to fit the resolution
image = ImageOps.exif_transpose(image)
image.thumbnail((min(img_x, int(res_x)), min(img_y, int(res_y))), Image.ANTIALIAS)
# Save image to cache directory
try:
image.save(os.path.join(CACHE_PATH,f'{file_name}_{res_x}x{res_y}.{ext}'),
icc_profile=image_icc)
except OSError:
# This usually happens when saving a JPEG with an ICC profile,
# so we convert to RGB and try again
image = image.convert('RGB')
image.save(os.path.join(CACHE_PATH, f'{file_name}_{res_x}x{res_y}.{ext}'),
icc_profile=image_icc)
# No need to keep the image in memory, learned the hard way
image.close()
return os.path.join(CACHE_PATH, f'{file_name}_{res_x}x{res_y}.{ext}')