mirror of
https://github.com/Derpy-Leggies/OnlyLegs.git
synced 2025-06-29 11:36:16 +00:00
Move user data to ~/.config/onlylegs location
Update location of default themes folder
This commit is contained in:
parent
828167f762
commit
512f6f623e
31 changed files with 158 additions and 110 deletions
|
@ -5,37 +5,96 @@ print("""
|
|||
| |_| | | | | | |_| | |__| __/ (_| \\__ \\
|
||||
\\___/|_| |_|_|\\__, |_____\\___|\\__, |___/
|
||||
|___/ |___/
|
||||
Created by Fluffy Bean - Version 23.03.01
|
||||
Created by Fluffy Bean - Version 23.03.02
|
||||
""")
|
||||
|
||||
from flask import Flask, render_template
|
||||
from flask_compress import Compress
|
||||
from flask.helpers import get_root_path
|
||||
|
||||
from dotenv import load_dotenv
|
||||
import platformdirs
|
||||
|
||||
import yaml
|
||||
import os
|
||||
|
||||
print(f"Running at {get_root_path(__name__)}\n")
|
||||
# I could use something other than the config dir, but this works well enough
|
||||
user_dir = platformdirs.user_config_dir('onlylegs')
|
||||
if not os.path.exists(user_dir):
|
||||
os.makedirs(user_dir)
|
||||
print("Created user directory")
|
||||
# Location of instance folder, where sqlite db is stored
|
||||
instance_path = os.path.join(user_dir, 'instance')
|
||||
if not os.path.exists(instance_path):
|
||||
os.makedirs(instance_path)
|
||||
print("Created instance directory")
|
||||
|
||||
# Get environment variables
|
||||
if os.path.exists(os.path.join(user_dir, '.env')):
|
||||
load_dotenv(os.path.join(user_dir, '.env'))
|
||||
print("Loaded environment variables")
|
||||
else:
|
||||
conf = {
|
||||
'FLASK_SECRETE': 'dev',
|
||||
}
|
||||
# Create .env file with default values
|
||||
with open(os.path.join(user_dir, '.env'), 'w') as f:
|
||||
for key, value in conf.items():
|
||||
f.write(f"{key}={value}\n")
|
||||
print("Created default environment variables at:",
|
||||
os.path.join(user_dir, '.env'),
|
||||
"\nCHANGE THESE VALUES USING TEHE GALLERY!")
|
||||
|
||||
# Get config file
|
||||
if os.path.exists(os.path.join(user_dir, 'conf.yml')):
|
||||
with open(os.path.join(user_dir, 'conf.yml'), 'r') as f:
|
||||
conf = yaml.load(f, Loader=yaml.FullLoader)
|
||||
print("Loaded gallery config")
|
||||
else:
|
||||
conf = {
|
||||
'admin': {
|
||||
'name': 'Real Person',
|
||||
'username': 'User',
|
||||
'email': 'real-email@some.place'
|
||||
},
|
||||
'upload': {
|
||||
'allowed-extensions': {
|
||||
'jpg': 'jpeg',
|
||||
'jpeg': 'jpeg',
|
||||
'png': 'png',
|
||||
'webp': 'webp'
|
||||
},
|
||||
'max-size': 69,
|
||||
'rename': 'GWA_\{\{username\}\}_\{\{time\}\}'
|
||||
},
|
||||
'website': {
|
||||
'name': 'OnlyLegs',
|
||||
'motto': 'Gwa Gwa',
|
||||
'language': 'english'
|
||||
}
|
||||
}
|
||||
# Create yaml config file with default values
|
||||
with open(os.path.join(user_dir, 'conf.yml'), 'w') as f:
|
||||
yaml.dump(conf, f, default_flow_style=False)
|
||||
print("Created default gallery config at:",
|
||||
os.path.join(user_dir, 'conf.yml'),
|
||||
"\nCHANGE THESE VALUES USING TEHE GALLERY!")
|
||||
|
||||
# Load logger
|
||||
from .logger import logger
|
||||
|
||||
logger.innit_logger()
|
||||
|
||||
|
||||
def create_app(test_config=None):
|
||||
# create and configure the app
|
||||
app = Flask(__name__)
|
||||
app = Flask(__name__, instance_path=instance_path)
|
||||
compress = Compress()
|
||||
|
||||
# Get environment variables
|
||||
load_dotenv(os.path.join(app.root_path, 'user', '.env'))
|
||||
print("Loaded environment variables")
|
||||
|
||||
# Get config file
|
||||
with open(os.path.join(app.root_path, 'user', 'conf.yml'), 'r') as f:
|
||||
conf = yaml.load(f, Loader=yaml.FullLoader)
|
||||
print("Loaded gallery config")
|
||||
|
||||
# App configuration
|
||||
app.config.from_mapping(
|
||||
SECRET_KEY=os.environ.get('FLASK_SECRET'),
|
||||
DATABASE=os.path.join(app.instance_path, 'gallery.sqlite'),
|
||||
UPLOAD_FOLDER=os.path.join(app.root_path, 'user', 'uploads'),
|
||||
UPLOAD_FOLDER=os.path.join(user_dir, 'uploads'),
|
||||
MAX_CONTENT_LENGTH=1024 * 1024 * conf['upload']['max-size'],
|
||||
ALLOWED_EXTENSIONS=conf['upload']['allowed-extensions'],
|
||||
WEBSITE=conf['website'],
|
||||
|
@ -61,10 +120,6 @@ def create_app(test_config=None):
|
|||
# Load theme
|
||||
from . import sassy
|
||||
sassy.compile('default', app.root_path)
|
||||
|
||||
# Load logger
|
||||
from .logger import logger
|
||||
logger.innit_logger(app)
|
||||
|
||||
@app.errorhandler(405)
|
||||
def method_not_allowed(e):
|
||||
|
@ -104,7 +159,7 @@ def create_app(test_config=None):
|
|||
from . import routing
|
||||
app.register_blueprint(routing.blueprint)
|
||||
app.add_url_rule('/', endpoint='index')
|
||||
|
||||
|
||||
# Load routes for settings
|
||||
from . import settings
|
||||
app.register_blueprint(settings.blueprint)
|
||||
|
|
|
@ -4,7 +4,7 @@ from werkzeug.utils import secure_filename
|
|||
from gallery.auth import login_required
|
||||
from gallery.db import get_db
|
||||
|
||||
from PIL import Image, ImageOps
|
||||
from PIL import Image, ImageOps, ImageFilter
|
||||
from . import metadata as mt
|
||||
|
||||
from .logger import logger
|
||||
|
@ -12,20 +12,30 @@ from .logger import logger
|
|||
from uuid import uuid4
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
|
||||
blueprint = Blueprint('api', __name__, url_prefix='/api')
|
||||
|
||||
|
||||
@blueprint.route('/uploads/<file>/<int:quality>', methods=['GET'])
|
||||
def uploads(file, quality):
|
||||
# If quality is 0, return original file
|
||||
if quality == 0:
|
||||
@blueprint.route('/uploads/<file>', methods=['GET'])
|
||||
def uploads(file):
|
||||
# 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 to image,
|
||||
# such as blur for NSFW images
|
||||
|
||||
# if no args are passed, return the raw file
|
||||
if width == 0 and height == 0 and not filtered:
|
||||
return send_from_directory(current_app.config['UPLOAD_FOLDER'],
|
||||
secure_filename(file),
|
||||
as_attachment=True)
|
||||
|
||||
# Set variables
|
||||
# Of either width or height is 0, set it to the other value to keep aspect ratio
|
||||
if width > 0 and height == 0:
|
||||
height = width
|
||||
elif width == 0 and height > 0:
|
||||
width = height
|
||||
|
||||
set_ext = current_app.config['ALLOWED_EXTENSIONS']
|
||||
buff = io.BytesIO()
|
||||
|
||||
|
@ -33,11 +43,11 @@ def uploads(file, quality):
|
|||
try:
|
||||
img = Image.open(
|
||||
os.path.join(current_app.config['UPLOAD_FOLDER'],
|
||||
secure_filename(file)))
|
||||
secure_filename(file)))
|
||||
except Exception as e:
|
||||
logger.server(600, f"Error opening image: {e}")
|
||||
abort(500)
|
||||
|
||||
|
||||
img_ext = os.path.splitext(secure_filename(file))[-1].lower().replace(
|
||||
'.', '')
|
||||
img_ext = set_ext[img_ext]
|
||||
|
@ -45,8 +55,15 @@ def uploads(file, quality):
|
|||
"icc_profile") # Get ICC profile as it alters colours
|
||||
|
||||
# Resize image and orientate correctly
|
||||
img.thumbnail((quality, quality), Image.LANCZOS)
|
||||
img.thumbnail((width, height), Image.LANCZOS)
|
||||
img = ImageOps.exif_transpose(img)
|
||||
|
||||
# TODO: Add filters
|
||||
# If has NSFW tag, blur image, etc.
|
||||
if filtered:
|
||||
#pass
|
||||
img = img.filter(ImageFilter.GaussianBlur(20))
|
||||
|
||||
try:
|
||||
img.save(buff, img_ext, icc_profile=img_icc)
|
||||
except OSError:
|
||||
|
@ -57,7 +74,7 @@ def uploads(file, quality):
|
|||
except:
|
||||
logger.server(600, f"Error resizing image: {file}")
|
||||
abort(500)
|
||||
|
||||
|
||||
img.close()
|
||||
|
||||
# Seek to beginning of buffer and return
|
||||
|
@ -74,13 +91,14 @@ def upload():
|
|||
if not form_file:
|
||||
return abort(404)
|
||||
|
||||
img_ext = os.path.splitext(secure_filename(form_file.filename))[-1].replace('.', '').lower()
|
||||
img_ext = os.path.splitext(secure_filename(
|
||||
form_file.filename))[-1].replace('.', '').lower()
|
||||
img_name = f"GWAGWA_{uuid4().__str__()}.{img_ext}"
|
||||
|
||||
if not img_ext in current_app.config['ALLOWED_EXTENSIONS'].keys():
|
||||
logger.add(303, f"File extension not allowed: {img_ext}")
|
||||
abort(403)
|
||||
|
||||
|
||||
if os.path.isdir(current_app.config['UPLOAD_FOLDER']) == False:
|
||||
os.mkdir(current_app.config['UPLOAD_FOLDER'])
|
||||
|
||||
|
@ -94,7 +112,7 @@ def upload():
|
|||
except Exception as e:
|
||||
logger.server(600, f"Error saving to database: {e}")
|
||||
abort(500)
|
||||
|
||||
|
||||
# Save file
|
||||
try:
|
||||
form_file.save(
|
||||
|
@ -154,17 +172,18 @@ def metadata(id):
|
|||
|
||||
return jsonify(exif)
|
||||
|
||||
|
||||
@blueprint.route('/logfile')
|
||||
@login_required
|
||||
def logfile():
|
||||
filename = logger.filename()
|
||||
log_dict = {}
|
||||
i = 0
|
||||
|
||||
|
||||
with open(filename) as f:
|
||||
for line in f:
|
||||
line = line.split(' : ')
|
||||
|
||||
|
||||
event = line[0].strip().split(' ')
|
||||
event_data = {
|
||||
'date': event[0],
|
||||
|
@ -172,7 +191,7 @@ def logfile():
|
|||
'severity': event[2],
|
||||
'owner': event[3]
|
||||
}
|
||||
|
||||
|
||||
message = line[1].strip()
|
||||
try:
|
||||
message_data = {
|
||||
|
@ -180,16 +199,10 @@ def logfile():
|
|||
'message': message[5:].strip()
|
||||
}
|
||||
except:
|
||||
message_data = {
|
||||
'code': 0,
|
||||
'message': message
|
||||
}
|
||||
|
||||
log_dict[i] = {
|
||||
'event': event_data,
|
||||
'message': message_data
|
||||
}
|
||||
|
||||
i += 1 # Line number, starts at 0
|
||||
|
||||
message_data = {'code': 0, 'message': message}
|
||||
|
||||
log_dict[i] = {'event': event_data, 'message': message_data}
|
||||
|
||||
i += 1 # Line number, starts at 0
|
||||
|
||||
return jsonify(log_dict)
|
|
@ -1,14 +1,15 @@
|
|||
import logging
|
||||
import os
|
||||
from datetime import datetime
|
||||
import platformdirs
|
||||
|
||||
# Prevent werkzeug from logging
|
||||
logging.getLogger('werkzeug').disabled = True
|
||||
|
||||
|
||||
class logger:
|
||||
def innit_logger(app):
|
||||
filepath = os.path.join(app.root_path, 'user', 'logs')
|
||||
def innit_logger():
|
||||
filepath = os.path.join(platformdirs.user_config_dir('onlylegs'), 'logs')
|
||||
#filename = f'onlylogs_{datetime.now().strftime("%Y%m%d")}.log'
|
||||
filename = 'only.log'
|
||||
|
||||
|
|
|
@ -11,8 +11,8 @@ class compile():
|
|||
def __init__(self, theme, dir):
|
||||
print(f"Loading '{theme}' theme...")
|
||||
|
||||
theme_path = os.path.join(dir, 'user', 'themes', theme)
|
||||
font_path = os.path.join(dir, 'user', 'themes', theme, 'fonts')
|
||||
theme_path = os.path.join(dir, 'themes', theme)
|
||||
font_path = os.path.join(dir, 'themes', theme, 'fonts')
|
||||
dest = os.path.join(dir, 'static', 'theme')
|
||||
|
||||
# print(f"Theme path: {theme_path}")
|
||||
|
|
|
@ -2,11 +2,10 @@ function showLogin() {
|
|||
popUpShow(
|
||||
'idk what to put here, just login please',
|
||||
'Need an account? <span class="pop-up__link" onclick="showRegister()">Register!</span>',
|
||||
'',
|
||||
'<form onsubmit="return login(event)">\
|
||||
'<button class="pop-up__btn pop-up__btn-primary-fill" form="loginForm" type="submit">Login</button>',
|
||||
'<form id="loginForm" onsubmit="return login(event)">\
|
||||
<input class="pop-up__input" type="text" placeholder="Namey" id="username"/>\
|
||||
<input class="pop-up__input" type="password" placeholder="Passywassy" id="password"/>\
|
||||
<button class="pop-up__btn pop-up__btn-primary-fill">Login</button>\
|
||||
</form>'
|
||||
);
|
||||
};
|
||||
|
@ -14,13 +13,12 @@ function showRegister() {
|
|||
popUpShow(
|
||||
'Who are you?',
|
||||
'Already have an account? <span class="pop-up__link" onclick="showLogin()">Login!</span>',
|
||||
'',
|
||||
'<form onsubmit="return register(event)">\
|
||||
'<button class="pop-up__btn pop-up__btn-primary-fill" form="registerForm" type="submit">Register</button>',
|
||||
'<form id="registerForm" onsubmit="return register(event)">\
|
||||
<input class="pop-up__input" type="text" placeholder="Namey" id="username"/>\
|
||||
<input class="pop-up__input" type="text" placeholder="E mail!" id="email"/>\
|
||||
<input class="pop-up__input" type="password" placeholder="Passywassy" id="password"/>\
|
||||
<input class="pop-up__input" type="password" placeholder="Passywassy again!" id="password-repeat"/>\
|
||||
<button class="pop-up__btn pop-up__btn-primary-fill">Register</button>\
|
||||
</form>'
|
||||
);
|
||||
};
|
||||
|
|
|
@ -157,4 +157,12 @@ function popupDissmiss() {
|
|||
setTimeout(function() {
|
||||
popup.classList = 'pop-up';
|
||||
}, 200);
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('keydown', function(event) {
|
||||
if (event.key === 'Escape') {
|
||||
if (document.querySelector('.pop-up').classList.contains('pop-up__active')) {
|
||||
popupDissmiss();
|
||||
}
|
||||
}
|
||||
});
|
|
@ -2,13 +2,12 @@ function showUpload() {
|
|||
popUpShow(
|
||||
'Upload funny stuff',
|
||||
'May the world see your stuff 👀',
|
||||
'',
|
||||
'<form onsubmit="return uploadFile(event)">\
|
||||
'<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"/>\
|
||||
<button class="pop-up__btn pop-up__btn-primary-fill">Upload</button>\
|
||||
</form>'
|
||||
);
|
||||
};
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
{% block header %}
|
||||
<div class="background-decoration">
|
||||
<img src="/api/uploads/{{ image['file_name'] }}/1000" onload="imgFade(this)" style="opacity:0;"/>
|
||||
<img src="/api/uploads/{{ image['file_name'] }}?w=1000&h=1000" onload="imgFade(this)" style="opacity:0;"/>
|
||||
<span></span>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@ -15,7 +15,7 @@
|
|||
|
||||
<div class="image-container">
|
||||
<img
|
||||
src="/api/uploads/{{ image['file_name'] }}/1000"
|
||||
src="/api/uploads/{{ image['file_name'] }}?w=1000&h=1000"
|
||||
onload="imgFade(this)" style="opacity:0;"
|
||||
onerror="this.src='/static/images/error.png'"
|
||||
width="{{ exif['File']['Width']['raw'] }}"
|
||||
|
@ -227,14 +227,14 @@
|
|||
$('.image-fullscreen').removeClass('image-fullscreen__active image-fullscreen__hide');
|
||||
}, 200);
|
||||
});
|
||||
|
||||
$('#img-fullscreen').click(function() {
|
||||
$('.image-fullscreen').addClass('image-fullscreen__active');
|
||||
|
||||
if ($('.image-fullscreen img').attr('src') == '') {
|
||||
$('.image-fullscreen img').attr('src', '/api/uploads/{{ image['file_name'] }}/0');
|
||||
$('.image-fullscreen img').attr('src', '/api/uploads/{{ image['file_name'] }}');
|
||||
}
|
||||
});
|
||||
|
||||
$('#img-share').click(function() {
|
||||
try {
|
||||
navigator.clipboard.writeText(window.location.href);
|
||||
|
@ -253,7 +253,7 @@
|
|||
'DESTRUCTION!!!!!!',
|
||||
'This will delete the image and all of its data!!! This action is irreversible!!!!! Are you sure you want to do this?????',
|
||||
'<button class="pop-up__btn pop-up__btn-critical-fill" onclick="deleteImage()">Dewww eeeet!</button>',
|
||||
'<img src="/api/uploads/{{ image['file_name'] }}/1000" />'
|
||||
'<img src="/api/uploads/{{ image['file_name'] }}?w=1000&h=1000" />'
|
||||
);
|
||||
});
|
||||
$('#img-edit').click(function() {
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
var image = images[i];
|
||||
if (image.getBoundingClientRect().top < window.innerHeight && image.getBoundingClientRect().bottom > 0) {
|
||||
if (!image.src) {
|
||||
image.src = `/api/uploads/${image.getAttribute('data-src')}/400`
|
||||
image.src = `/api/uploads/${image.getAttribute('data-src')}?w=500&h=500`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
|
||||
.pop-up-wrapper
|
||||
margin: 0
|
||||
padding: 0.5rem
|
||||
padding: 0
|
||||
|
||||
width: 621px
|
||||
height: auto
|
||||
|
@ -57,7 +57,6 @@
|
|||
|
||||
display: flex
|
||||
flex-direction: column
|
||||
gap: 0.5rem
|
||||
|
||||
background-color: $white
|
||||
border-radius: $rad
|
||||
|
@ -69,7 +68,7 @@
|
|||
|
||||
.pop-up-content
|
||||
margin: 0
|
||||
padding: 0
|
||||
padding: 0.5rem 0.5rem 0
|
||||
|
||||
width: 100%
|
||||
height: auto
|
||||
|
@ -138,22 +137,21 @@
|
|||
|
||||
.pop-up-controlls
|
||||
margin: 0
|
||||
padding: 0
|
||||
padding: 0.5rem
|
||||
|
||||
width: 100%
|
||||
height: auto
|
||||
|
||||
display: flex
|
||||
flex-direction: column
|
||||
flex-direction: row
|
||||
justify-content: flex-end
|
||||
gap: 0.5rem
|
||||
|
||||
justify-content: center
|
||||
|
||||
.pop-up__btn
|
||||
margin: 0
|
||||
padding: 0.5rem
|
||||
padding: 0.5rem 1rem
|
||||
|
||||
width: 100%
|
||||
width: auto
|
||||
height: 2.5rem
|
||||
|
||||
display: flex
|
||||
|
@ -255,6 +253,13 @@
|
|||
|
||||
img
|
||||
max-height: 50vh
|
||||
|
||||
.pop-up-controlls
|
||||
flex-direction: column
|
||||
justify-content: center
|
||||
|
||||
.pop-up__btn
|
||||
width: 100%
|
||||
|
||||
.pop-up__active
|
||||
opacity: 1
|
|
@ -86,8 +86,6 @@
|
|||
object-fit: contain
|
||||
object-position: center
|
||||
|
||||
border-radius: $rad
|
||||
|
||||
.image-info__container
|
||||
margin: 0
|
||||
padding: 0
|
|
@ -1,9 +0,0 @@
|
|||
# EMAIL CONFIGURATION
|
||||
EMAIL_HOST = #smtp.gmail.com
|
||||
EMAIL_PORT = #465
|
||||
EMAIL_HOST_USER = #your email
|
||||
EMAIL_HOST_PASSWORD = #your password
|
||||
EMAIL_USE_TLS = #True
|
||||
|
||||
# FLASK SECRETE KEY, DONT LOOSE IT!!!!!!!
|
||||
FLASK_SECRET = #your secret key
|
|
@ -1,21 +0,0 @@
|
|||
# THIS IS AN EXAMPLE CONFIG, RENAME THIS TO conf.yml TO USE
|
||||
|
||||
admin:
|
||||
name: Real Person
|
||||
username: User
|
||||
email: real-email@some.place
|
||||
|
||||
upload:
|
||||
allowed-extensions:
|
||||
- .png
|
||||
- .jpg
|
||||
- .jpeg
|
||||
- .webp
|
||||
max-size: 69MB
|
||||
rename: GWA_{{username}}_{{time}}
|
||||
|
||||
website:
|
||||
name: OnlyLegs
|
||||
motto: Gwa Gwa
|
||||
language: english # Placeholder for future language support endevours
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue