Fix errors in metadata parsing

Remove useless extra checks in metadata parser
Add Flask-Caching, need to test how helpfull this is
This commit is contained in:
Michał Gdula 2023-03-08 09:01:20 +00:00
parent 91278e2d11
commit 99c1d81869
27 changed files with 504 additions and 125 deletions

View file

@ -15,6 +15,7 @@ import logging
# Flask
from flask_compress import Compress
from flask_caching import Cache
from flask import Flask, render_template
# Configuration
@ -73,6 +74,7 @@ def create_app(test_config=None):
"""
app = Flask(__name__,instance_path=INSTANCE_PATH)
compress = Compress()
cache = Cache(config={'CACHE_TYPE': 'SimpleCache', 'CACHE_DEFAULT_TIMEOUT': 69})
# App configuration
app.config.from_mapping(
@ -146,4 +148,5 @@ def create_app(test_config=None):
app.register_blueprint(api.blueprint)
compress.init_app(app)
cache.init_app(app)
return app

View file

@ -13,7 +13,7 @@ from flask import (
from werkzeug.utils import secure_filename
from colorthief import ColorThief
from PIL import Image, ImageOps # ImageFilter
from PIL import Image, ImageOps, ImageFilter
from sqlalchemy.orm import sessionmaker
from gallery.auth import login_required
@ -33,11 +33,13 @@ def uploads(file):
Returns a file from the uploads folder
w and h are the width and height of the image for resizing
f is whether to apply filters to the image, such as blurring NSFW images
b is whether to force blur the image, even if it's not NSFW
"""
# Get args
width = request.args.get('w', default=0, type=int) # Width of image
height = request.args.get('h', default=0, type=int) # Height of image
filtered = request.args.get('f', default=False, type=bool) # Whether to apply filters
filtered = request.args.get('f', default=False, type=bool) # Whether to apply filters
blur = request.args.get('b', default=False, type=bool) # Whether to force blur
# if no args are passed, return the raw file
if width == 0 and height == 0 and not filtered:
@ -78,6 +80,10 @@ def uploads(file):
if filtered:
#img = img.filter(ImageFilter.GaussianBlur(20))
pass
# If forced to blur, blur image
if blur:
img = img.filter(ImageFilter.GaussianBlur(20))
try:
img.save(buff, img_ext, icc_profile=img_icc)

View file

@ -69,6 +69,7 @@ class Metadata:
exif['Photographer'][PHOTOGRAHER_MAPPING[data][0]] = {
'raw': encoded_exif[data],
}
continue
elif data in CAMERA_MAPPING:
if len(CAMERA_MAPPING[data]) == 2:
# Camera - Exif Tag name
@ -81,6 +82,7 @@ class Metadata:
exif['Camera'][CAMERA_MAPPING[data][0]] = {
'raw': encoded_exif[data],
}
continue
elif data in SOFTWARE_MAPPING:
if len(SOFTWARE_MAPPING[data]) == 2:
exif['Software'][SOFTWARE_MAPPING[data][0]] = {
@ -92,6 +94,7 @@ class Metadata:
exif['Software'][SOFTWARE_MAPPING[data][0]] = {
'raw': encoded_exif[data],
}
continue
elif data in FILE_MAPPING:
if len(FILE_MAPPING[data]) == 2:
exif['File'][FILE_MAPPING[data][0]] = {

View file

@ -352,6 +352,7 @@ def orientation(value):
Maps the value of the orientation to a human readable format
"""
value_map = {
0: 'Undefined',
1: 'Horizontal (normal)',
2: 'Mirror horizontal',
3: 'Rotate 180',

View file

@ -31,7 +31,7 @@ CAMERA_MAPPING = {
'ISOSpeedRatings': ['ISO Speed Ratings', 'iso'],
'ISOSpeed': ['ISO Speed', 'iso'],
'SensitivityType': ['Sensitivity Type', 'sensitivity_type'],
'ExposureBiasValue': ['Exposure Bias', 'ev'],
'ExposureBiasValue': ['Exposure Bias', 'exposure'],
'ExposureTime': ['Exposure Time', 'shutter'],
'ExposureMode': ['Exposure Mode', 'exposure_mode'],
'ExposureProgram': ['Exposure Program', 'exposure_program'],

View file

@ -2,8 +2,9 @@
Onlylegs Gallery - Routing
"""
import os
from datetime import datetime as dt
from flask import Blueprint, render_template, current_app
from flask import Blueprint, render_template, current_app, request, g
from werkzeug.exceptions import abort
from sqlalchemy.orm import sessionmaker
@ -23,9 +24,10 @@ def index():
Home page of the website, shows the feed of latest images
"""
images = db_session.query(db.Posts.file_name,
db.Posts.id,
db.Posts.created_at
).order_by(db.Posts.id.desc()).all()
db.Posts.image_colours,
db.Posts.author_id,
db.Posts.created_at,
db.Posts.id).order_by(db.Posts.id.desc()).all()
return render_template('index.html',
images=images,
@ -47,12 +49,25 @@ def image(image_id):
return render_template('image.html', image=img, exif=img.image_exif)
@blueprint.route('/group')
@blueprint.route('/group', methods=['GET', 'POST'])
def groups():
"""
Group overview, shows all image groups
"""
return render_template('group.html', group_id='gwa gwa')
if request.method == 'GET':
groups = db_session.query(db.Groups.name, db.Groups.author_id).all()
return render_template('group.html', groups=groups)
elif request.method == 'POST':
group_name = request.form['name']
group_description = request.form['description']
group_author = g.user.id
new_group = db.Groups(name=group_name, description=group_description, author_id=group_author, created_at=dt.now())
db_session.add(new_group)
return ':3'
@blueprint.route('/group/<int:group_id>')
def group(group_id):
@ -73,4 +88,4 @@ def profile_id(user_id):
"""
Shows user ofa given id, displays their uploads and other info
"""
return render_template('profile.html', user_id=user_id)
return render_template('profile.html', user_id=user_id)

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 19 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

View file

@ -1,20 +1,9 @@
function showUpload() {
popUpShow(
'Upload funny stuff',
'May the world see your stuff 👀',
'<button class="pop-up__btn pop-up__btn-primary-fill" form="uploadForm" type"submit">Upload</button>',
'<form id="uploadForm" onsubmit="return uploadFile(event)">\
<input class="pop-up__input" type="file" id="file"/>\
<input class="pop-up__input" type="text" placeholder="alt" id="alt"/>\
<input class="pop-up__input" type="text" placeholder="description" id="description"/>\
<input class="pop-up__input" type="text" placeholder="tags" id="tags"/>\
</form>'
);
};
function uploadFile(){
// AJAX takes control of subby form
event.preventDefault();
const jobList = document.querySelector(".upload-jobs");
// Check for empty upload
if ($("#file").val() === "") {
addNotification("Please select a file to upload", 2);
@ -35,32 +24,58 @@ function uploadFile(){
contentType: false,
processData: false,
beforeSend: function() {
console.log("Uploading...");
jobContainer = document.createElement("div");
jobContainer.classList.add("job");
jobStatus = document.createElement("span");
jobStatus.classList.add("job__status");
jobStatus.innerHTML = "Uploading...";
jobProgress = document.createElement("span");
jobProgress.classList.add("progress");
jobImg = document.createElement("img");
jobImg.src = URL.createObjectURL($("#file").prop("files")[0]);
jobImgFilter = document.createElement("span");
jobImgFilter.classList.add("img-filter");
jobContainer.appendChild(jobStatus);
jobContainer.appendChild(jobProgress);
jobContainer.appendChild(jobImg);
jobContainer.appendChild(jobImgFilter);
jobList.appendChild(jobContainer);
},
success: function (response) {
addNotification("File uploaded successfully!", 1);
console.log('File processed successfully');
jobContainer.classList.add("success");
jobStatus.innerHTML = "Uploaded!";
if (!document.querySelector(".upload-panel").classList.contains("open")) {
addNotification("Image uploaded successfully", 1);
}
},
error: function (response) {
jobContainer.classList.add("critical");
switch (response.status) {
case 500:
addNotification('Server exploded, F\'s in chat', 2);
jobStatus.innerHTML = "Server exploded, F's in chat";
break;
case 400:
case 404:
addNotification('Error uploading. Blame yourself', 2);
jobStatus.innerHTML = "Error uploading. Blame yourself";
break;
case 403:
addNotification('None but devils play past here...', 2);
jobStatus.innerHTML = "None but devils play past here...";
break;
case 413:
addNotification('File too large!!!!!!', 3);
jobStatus.innerHTML = "File too large!!!!!!";
break;
default:
addNotification('Error uploading file, blame someone', 2);
jobStatus.innerHTML = "Error uploading file, blame someone";
break;
}
console.log('Error uploading file');
if (!document.querySelector(".upload-panel").classList.contains("open")) {
addNotification("Error uploading file", 2);
}
},
});
@ -70,4 +85,23 @@ function uploadFile(){
$("#description").val("");
$("#tags").val("");
}
};
};
function openUploadTab() {
// Open upload tab
const uploadTab = document.querySelector(".upload-panel");
uploadTab.style.display = "block";
setTimeout( function() {
uploadTab.classList.add("open");
}, 10);
}
function closeUploadTab() {
// Close upload tab
const uploadTab = document.querySelector(".upload-panel");
uploadTab.classList.remove("open");
setTimeout( function() {
uploadTab.style.display = "none";
}, 250);
}

View file

@ -1,15 +1,45 @@
{% extends 'layout.html' %}
{% block header %}
<div class="background-decoration">
<img src="{{ url_for('static', filename='images/background.svg') }}" onload="imgFade(this)" style="opacity:0;"/>
<div class="banner">
<img src="{{ url_for('static', filename='images/bg.svg') }}" onload="imgFade(this)" style="opacity:0;"/>
<span></span>
<div class="banner__content">
{% block banner_subtitle%}{% endblock %}
<h1>Groups</h1>
<p>gwa gwa</p>
</div>
</div>
{% endblock %}
{% block nav_groups %}navigation-item__selected{% endblock %}
{% block content %}
<h1>Image Group</h1>
<p>{{group_id}}</p>
<div class="gallery">
{% for group in groups %}
<a id="group-{{ group['id'] }}" class="gallery__item" href="/group/{{ group['id'] }}">
<span class="gallery__item-info">
<p>{{ group['id'] }}</p>
<h2><span class="time">{{ group['created_at'] }}</span></h2>
</span>
<img
class="gallery__item-group"
data-src="{{ group['file_name'] }}"
onload="imgFade(this)"
style="opacity:0;"
/>
</a>
{% endfor %}
</div>
<form action="/group" method="post" enctype="multipart/form-data">
<input type="text" name="name" placeholder="name">
<input type="text" name="description" placeholder="description">
<button type="submit">Submit</button>
</form>
{% endblock %}
{% block script %}
<script>
</script>
{% endblock %}

View file

@ -3,7 +3,7 @@
{% block header %}
<div class="background-decoration">
<img src="/api/uploads/{{ image['file_name'] }}?w=1000&h=1000" onload="imgFade(this)" style="opacity:0;"/>
<span></span>
<span style="background-image: linear-gradient(to top, rgba({{ image['image_colours'][0][0] }}, {{ image['image_colours'][0][1] }}, {{ image['image_colours'][0][2] }}, 1), transparent);"></span>
</div>
{% endblock %}
{% block wrapper_class %}image-wrapper{% endblock %}

View file

@ -2,7 +2,7 @@
{% block header %}
<div class="banner">
<img src="{{ url_for('static', filename='images/leaves.jpg') }}" onload="imgFade(this)" style="opacity:0;"/>
<img src="{{ url_for('static', filename='images/bg.svg') }}" onload="imgFade(this)" style="opacity:0;"/>
<span></span>
<div class="banner__content">
@ -19,9 +19,9 @@
{% block content %}
<div class="gallery">
{% for image in images %}
<a id="image-{{ image['id'] }}" class="gallery__item" href="/image/{{ image['id'] }}">
<a id="image-{{ image['id'] }}" class="gallery__item" href="/image/{{ image['id'] }}" style="background-color: rgb({{ image['image_colours'][0][0] }}, {{ image['image_colours'][0][1] }}, {{ image['image_colours'][0][2] }})">
<span class="gallery__item-info">
<p>{{ image['id'] }}</p>
<p></p>
<h2><span class="time">{{ image['created_at'] }}</span></h2>
</span>
<img
@ -59,15 +59,19 @@
};
if (document.referrer.includes('image')) {
var referrerId = document.referrer.split('/').pop();
var imgOffset = document.getElementById('image-' + referrerId).offsetTop;
var imgHeight = document.getElementById('image-' + referrerId).offsetHeight;
var windowHeight = window.innerHeight;
document.querySelector('html').style.scrollBehavior = 'auto';
window.scrollTo(0, imgOffset + (imgHeight / 2) - (windowHeight / 2));
document.querySelector('html').style.scrollBehavior = 'smooth';
try {
var referrerId = document.referrer.split('/').pop();
var imgOffset = document.getElementById('image-' + referrerId).offsetTop;
var imgHeight = document.getElementById('image-' + referrerId).offsetHeight;
var windowHeight = window.innerHeight;
document.querySelector('html').style.scrollBehavior = 'auto';
window.scrollTo(0, imgOffset + (imgHeight / 2) - (windowHeight / 2));
document.querySelector('html').style.scrollBehavior = 'smooth';
} catch (e) {
console.log(e);
}
}
</script>
{% endblock %}

View file

@ -18,8 +18,8 @@
<script src="{{ url_for('static', filename='js/login.js') }}" defer></script>
<!-- UI -->
<script src="{{ url_for('static', filename='js/ui/popup.js') }}" defer></script>
<script src="{{ url_for('static', filename='js/ui/notifications.js') }}" defer></script>
<script src="{{ url_for('static', filename='js/ui/popup.js') }}"></script>
<script src="{{ url_for('static', filename='js/ui/notifications.js') }}"></script>
</head>
<body>
<div class="wrapper">
@ -29,9 +29,9 @@
<path d="M11 8.414V14a1 1 0 0 1-2 0V8.414L6.464 10.95A1 1 0 1 1 5.05 9.536l4.243-4.243a.997.997 0 0 1 1.414 0l4.243 4.243a1 1 0 1 1-1.414 1.414L11 8.414zM10 20C4.477 20 0 15.523 0 10S4.477 0 10 0s10 4.477 10 10-4.477 10-10 10zm0-2a8 8 0 1 0 0-16 8 8 0 0 0 0 16z"></path>
</svg>
{% block header %}{% endblock %}
<div class="navigation">
<img src="{{url_for('static', filename='images/icon.png')}}" alt="Logo" class="logo" onload="imgFade(this)" style="opacity:0;">
<a href="{{url_for('gallery.index')}}" class="navigation-item {% block nav_home %}{% endblock %}">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-2 -2 24 24" width="24" fill="currentColor">
<path d="M2 8v10h12V8H2zm2-2V2a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2h-2v4a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h2zm2 0h8a2 2 0 0 1 2 2v4h2V2H6v4zm0 9a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm0-2a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"></path><path d="M7 6a3 3 0 1 1 6 0h-2a1 1 0 0 0-2 0H7zm1.864 13.518l2.725-4.672a1 1 0 0 1 1.6-.174l1.087 1.184 1.473-1.354-1.088-1.183a3 3 0 0 0-4.8.52L7.136 18.51l1.728 1.007zm6.512-12.969a2.994 2.994 0 0 1 3.285.77l1.088 1.183-1.473 1.354-1.087-1.184A1 1 0 0 0 16 8.457V8c0-.571-.24-1.087-.624-1.451z"></path>
@ -47,7 +47,7 @@
</a>
{% if g.user %}
<button class="navigation-item {% block nav_upload %}{% endblock %}" onclick="showUpload()">
<button class="navigation-item {% block nav_upload %}{% endblock %}" onclick="openUploadTab()">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -5 24 24" width="24" fill="currentColor">
<path d="M8 3.414v5.642a1 1 0 1 1-2 0V3.414L4.879 4.536A1 1 0 0 1 3.464 3.12L6.293.293a1 1 0 0 1 1.414 0l2.829 2.828A1 1 0 1 1 9.12 4.536L8 3.414zM1 12h12a1 1 0 0 1 0 2H1a1 1 0 0 1 0-2z"></path>
</svg>
@ -81,6 +81,8 @@
{% endif %}
</div>
{% block header %}{% endblock %}
<div class="content {% block wrapper_class %}{% endblock %}">
{% block content %}
{% endblock %}
@ -98,6 +100,22 @@
</div>
</div>
</div>
<div class="upload-panel">
<span class="click-off" onclick="closeUploadTab()"></span>
<div class="container">
<h3>Upload stuffs</h3>
<p>May the world see your stuff 👀</p>
<form id="uploadForm" onsubmit="return uploadFile(event)">
<input type="file" id="file"/>
<input type="text" placeholder="alt" id="alt"/>
<input type="text" placeholder="description" id="description"/>
<input type="text" placeholder="tags" id="tags"/>
<button type="submit">Upload</button>
</form>
<div class="upload-jobs"></div>
</div>
</div>
</div>
<script>

View file

@ -17,3 +17,9 @@
100%
left: 0%
height: 0
@keyframes uploadingLoop
0%
left: -100%
100%
left: 100%

View file

@ -6,6 +6,8 @@
@import "ui/notification"
@import "ui/pop-up"
@import "ui/upload-panel"
@import "ui/navigation"
@import "ui/content"
@import "ui/background"

View file

@ -42,6 +42,4 @@
width: 100%
height: 100%
background-image: linear-gradient(to bottom, rgba($white, 0), rgba($white, 1))
z-index: +1

View file

@ -9,13 +9,9 @@
top: 0
left: 3.5rem
background-color: $white
background-color: $black
color: $black
background-image: linear-gradient(to right, darken($white, 1%) 15%, darken($white, 10%) 35%, darken($white, 1%) 50%)
background-size: 1000px 640px
animation: imgLoading 1.8s linear infinite forwards
overflow: hidden
transition: opacity 0.3s ease-in-out
@ -27,7 +23,7 @@
width: 100%
height: 100%
background-color: $white
background-color: $black
object-fit: cover
object-position: center center

View file

@ -20,9 +20,9 @@
position: relative
background: linear-gradient(to right, darken($white, 1%) 15%, darken($white, 10%) 35%, darken($white, 1%) 50%)
background-size: 1000px 640px
animation: imgLoading 1.8s linear infinite forwards
// background: linear-gradient(to right, darken($white, 1%) 15%, darken($white, 10%) 35%, darken($white, 1%) 50%)
// background-size: 1000px 640px
// animation: imgLoading 1.8s linear infinite forwards
border-radius: $rad
box-sizing: border-box

View file

@ -22,6 +22,18 @@
> span
height: 100%
.logo
margin: 0
padding: 0
width: 3.5rem
height: 3.5rem
min-height: 3.5rem
display: flex
flex-direction: row
align-items: center
.navigation-item
margin: 0
padding: 1rem
@ -108,6 +120,9 @@
> span
display: none
.logo
display: none
.navigation-item
margin: 0.25rem
padding: 0

View file

@ -93,7 +93,7 @@
animation: notificationTimeout 5.1s linear
@each $name, $colour in (success: $succes, error: $critical, warning: $warning, info: $info)
@each $name, $colour in (success: $success, error: $critical, warning: $warning, info: $info)
.sniffle__notification--#{$name}
@include notification($colour)

View file

@ -25,7 +25,6 @@
left: 3.5rem
background-color: rgba($black, 0.8)
backdrop-filter: blur(1rem)
opacity: 0
z-index: 101

View file

@ -0,0 +1,219 @@
.upload-panel
position: fixed
top: 0
left: 0
display: none
width: 100%
height: 100vh
background-color: rgba($black, 0)
overflow: hidden
z-index: 68
transition: background-color 0.25s cubic-bezier(0.76, 0, 0.17, 1)
h3
margin: 0
padding: 0
font-size: 1.5rem
font-weight: 600
color: $white
p
margin: 0
padding: 0
font-size: 1rem
font-weight: 500
color: $white
form
margin: 0
padding: 0
width: 100%
display: flex
flex-direction: column
align-items: center
gap: 0.5rem
input
margin: 0
padding: 0.5rem 1rem
width: 100%
height: 2.5rem
font-size: 1rem
font-weight: 600
color: $white
background-color: $black2
border: none
border-radius: $rad-inner
&::placeholder
color: $white
button
margin: 0
padding: 0.5rem 1rem
width: 100%
height: 2.5rem
font-size: 1rem
font-weight: 600
color: $white
background-color: $primary
border: none
border-radius: $rad-inner
cursor: pointer
&:hover
background-color: $black2
color: $primary
.click-off
position: absolute
top: 0
left: 0
width: 100%
height: 100%
z-index: +1
.container
padding: 0.5rem
position: absolute
top: 0
left: calc(-400px + 3.5rem)
width: 400px
height: 100%
display: flex
flex-direction: column
gap: 1rem
background-color: $black
opacity: 0
z-index: +2
transition: left 0.25s cubic-bezier(0.76, 0, 0.17, 1), opacity 0.25s cubic-bezier(0.76, 0, 0.17, 1)
.upload-jobs
display: flex
flex-direction: column
gap: 0.5rem
border-radius: $rad
overflow-y: auto
.job
width: 100%
height: 5rem
min-height: 5rem
position: relative
display: flex
align-items: center
gap: 0.5rem
background-color: $black2
border-radius: $rad
overflow: hidden
img
position: absolute
top: 0
left: 0
width: 100%
height: 5rem
object-fit: cover
.img-filter
position: absolute
top: 0
left: 0
width: 100%
height: 100%
background-image: linear-gradient(to right, rgba($black, 0.8), rgba($black, 0))
.job__status
margin: 0
padding: 0
position: absolute
top: 0.5rem
left: 0.5rem
font-size: 1rem
font-weight: 600
color: $white
z-index: +3
transition: color 0.25s cubic-bezier(0.76, 0, 0.17, 1)
.progress
width: 100%
height: $rad-inner
position: absolute
bottom: 0
left: -100%
background-color: $primary
animation: uploadingLoop 1s cubic-bezier(0.76, 0, 0.17, 1) infinite
z-index: +5
transition: left 1s cubic-bezier(0.76, 0, 0.17, 1)
&.critical
.job__status, .progress
color: $critical
&.success
.job__status
color: $success
.progress
height: 0
animation: none
&.warning
.job__status, .progress
color: $warning
&.critical, &.success, &.warning
.progress
height: 0
&.open
background-color: rgba($black, 0.5)
.container
left: 3.5rem
opacity: 1

View file

@ -24,7 +24,6 @@
opacity: 0 // hide
background-color: rgba($black, 0.8)
backdrop-filter: blur(1rem)
z-index: 21
box-sizing: border-box
@ -86,6 +85,8 @@
object-fit: contain
object-position: center
// box-shadow: 0 0 0.5rem rgba($black, 0.5)
.image-info__container
margin: 0
padding: 0

View file

@ -12,7 +12,7 @@ $purple: #A988B0
$primary: $green
$warning: $orange
$critical: $red
$succes: $green
$success: $green
$info: $blue
$rad: 6px