mirror of
https://github.com/Derpy-Leggies/OnlyLegs.git
synced 2025-01-29 01:28:24 +00:00
Yeet old runner script as it was useless
Clean up code and styling
This commit is contained in:
parent
8a4fe891ef
commit
9821db72c6
115
onlylegs/app.py
115
onlylegs/app.py
|
@ -1,67 +1,55 @@
|
|||
"""
|
||||
Onlylegs Gallery
|
||||
This is the main app file, it loads all the other files and sets up the app
|
||||
This is the main app file, checks on app stability and runs all da shit
|
||||
"""
|
||||
import os
|
||||
import logging
|
||||
|
||||
from flask_assets import Bundle
|
||||
from flask_migrate import init as migrate_init
|
||||
|
||||
from flask import Flask, render_template, abort
|
||||
from flask import Flask, render_template, abort, request
|
||||
from werkzeug.exceptions import HTTPException
|
||||
from werkzeug.security import generate_password_hash
|
||||
|
||||
from onlylegs.utils import startup
|
||||
from onlylegs.extensions import db, migrate, login_manager, assets, compress, cache
|
||||
from onlylegs.config import INSTANCE_DIR, MIGRATIONS_DIR
|
||||
from onlylegs.config import INSTANCE_DIR, MIGRATIONS_DIR, APPLICATION_ROOT
|
||||
from onlylegs.models import Users
|
||||
from onlylegs.views import (
|
||||
index as view_index,
|
||||
image as view_image,
|
||||
group as view_group,
|
||||
settings as view_settings,
|
||||
profile as view_profile,
|
||||
|
||||
from onlylegs.views.index import blueprint as view_index
|
||||
from onlylegs.views.image import blueprint as view_image
|
||||
from onlylegs.views.group import blueprint as view_group
|
||||
from onlylegs.views.settings import blueprint as view_settings
|
||||
from onlylegs.views.profile import blueprint as view_profile
|
||||
from onlylegs.api import blueprint as api
|
||||
from onlylegs.auth import blueprint as view_auth
|
||||
from onlylegs.filters import blueprint as filters
|
||||
|
||||
|
||||
logging.getLogger("werkzeug").disabled = True
|
||||
logging.basicConfig(
|
||||
filename=os.path.join(APPLICATION_ROOT, "only.log"),
|
||||
level=logging.INFO,
|
||||
datefmt="%Y-%m-%d %H:%M:%S",
|
||||
format="%(asctime)s %(levelname)s %(name)s %(threadName)s : %(message)s",
|
||||
encoding="utf-8",
|
||||
)
|
||||
from onlylegs import api
|
||||
from onlylegs import auth as view_auth
|
||||
from onlylegs import filters
|
||||
|
||||
|
||||
app = Flask(__name__, instance_path=INSTANCE_DIR)
|
||||
app.config.from_pyfile("config.py")
|
||||
|
||||
# DATABASE
|
||||
db.init_app(app)
|
||||
migrate.init_app(app, db, directory=MIGRATIONS_DIR)
|
||||
|
||||
# If database file doesn't exist, create it
|
||||
# App Sanity Checks
|
||||
startup.check_dirs()
|
||||
startup.check_env()
|
||||
startup.check_conf()
|
||||
|
||||
if not os.path.exists(os.path.join(INSTANCE_DIR, "gallery.sqlite3")):
|
||||
print("Creating database")
|
||||
with app.app_context():
|
||||
db.create_all()
|
||||
startup.make_admin_user(app)
|
||||
migrate_init(directory=MIGRATIONS_DIR)
|
||||
|
||||
register_user = Users(
|
||||
username=app.config["ADMIN_CONF"]["username"],
|
||||
email=app.config["ADMIN_CONF"]["email"],
|
||||
password=generate_password_hash("changeme!", method="sha256"),
|
||||
)
|
||||
db.session.add(register_user)
|
||||
db.session.commit()
|
||||
|
||||
print(
|
||||
"""
|
||||
####################################################
|
||||
# DEFAULT ADMIN USER GENERATED WITH GIVEN USERNAME #
|
||||
# THE DEFAULT PASSWORD "changeme!" HAS BEEN USED, #
|
||||
# PLEASE UPDATE IT IN THE SETTINGS! #
|
||||
####################################################
|
||||
"""
|
||||
)
|
||||
|
||||
# Check if migrations directory exists, if not create it
|
||||
with app.app_context():
|
||||
if not os.path.exists(MIGRATIONS_DIR):
|
||||
print("Creating migrations directory")
|
||||
migrate_init(directory=MIGRATIONS_DIR)
|
||||
|
||||
# LOGIN MANAGER
|
||||
# can also set session_protection to "strong"
|
||||
|
@ -90,40 +78,41 @@ def error_page(err):
|
|||
"""
|
||||
if not isinstance(err, HTTPException):
|
||||
abort(500)
|
||||
return (
|
||||
render_template("error.html", error=err.code, msg=err.description),
|
||||
err.code,
|
||||
)
|
||||
|
||||
if request.method == "GET":
|
||||
return (
|
||||
render_template("error.html", error=err.code, msg=err.description),
|
||||
err.code,
|
||||
)
|
||||
else:
|
||||
return str(err.code) + ": " + err.description, err.code
|
||||
|
||||
|
||||
# ASSETS
|
||||
assets.init_app(app)
|
||||
|
||||
scripts = Bundle(
|
||||
"js/*.js", output="gen/js.js", depends="js/*.js"
|
||||
) # filter jsmin is broken :c
|
||||
styles = Bundle(
|
||||
page_scripts = Bundle(
|
||||
"js/*.js", filters="jsmin", output="gen/main.js", depends="js/*.js"
|
||||
)
|
||||
page_styling = Bundle(
|
||||
"sass/style.sass",
|
||||
filters="libsass, cssmin",
|
||||
output="gen/styles.css",
|
||||
depends="sass/**/*.sass",
|
||||
)
|
||||
|
||||
assets.register("scripts", scripts)
|
||||
assets.register("styles", styles)
|
||||
assets.register("scripts", page_scripts)
|
||||
assets.register("styles", page_styling)
|
||||
|
||||
# BLUEPRINTS
|
||||
app.register_blueprint(view_auth.blueprint)
|
||||
app.register_blueprint(view_index.blueprint)
|
||||
app.register_blueprint(view_image.blueprint)
|
||||
app.register_blueprint(view_group.blueprint)
|
||||
app.register_blueprint(view_profile.blueprint)
|
||||
app.register_blueprint(view_settings.blueprint)
|
||||
|
||||
app.register_blueprint(api.blueprint)
|
||||
|
||||
# FILTERS
|
||||
app.register_blueprint(filters.blueprint)
|
||||
app.register_blueprint(view_auth)
|
||||
app.register_blueprint(view_index)
|
||||
app.register_blueprint(view_image)
|
||||
app.register_blueprint(view_group)
|
||||
app.register_blueprint(view_profile)
|
||||
app.register_blueprint(view_settings)
|
||||
app.register_blueprint(api)
|
||||
app.register_blueprint(filters)
|
||||
|
||||
# CACHE AND COMPRESS
|
||||
cache.init_app(app)
|
||||
|
|
|
@ -9,16 +9,17 @@ from yaml import safe_load
|
|||
|
||||
|
||||
# Set dirs
|
||||
user_dir = platformdirs.user_config_dir("onlylegs")
|
||||
instance_dir = os.path.join(user_dir, "instance")
|
||||
APPLICATION_ROOT = platformdirs.user_config_dir("onlylegs")
|
||||
|
||||
# Load environment variables
|
||||
# print("Loading environment variables...")
|
||||
load_dotenv(os.path.join(user_dir, ".env"))
|
||||
load_dotenv(os.path.join(APPLICATION_ROOT, ".env"))
|
||||
|
||||
# Load config from user dir
|
||||
# print("Loading config...")
|
||||
with open(os.path.join(user_dir, "conf.yml"), encoding="utf-8", mode="r") as file:
|
||||
with open(
|
||||
os.path.join(APPLICATION_ROOT, "conf.yml"), encoding="utf-8", mode="r"
|
||||
) as file:
|
||||
conf = safe_load(file)
|
||||
|
||||
|
||||
|
@ -34,13 +35,13 @@ UPLOAD_CONF = conf["upload"]
|
|||
WEBSITE_CONF = conf["website"]
|
||||
|
||||
# Directories
|
||||
UPLOAD_FOLDER = os.path.join(user_dir, "media", "uploads")
|
||||
CACHE_FOLDER = os.path.join(user_dir, "media", "cache")
|
||||
PFP_FOLDER = os.path.join(user_dir, "media", "pfp")
|
||||
MEDIA_FOLDER = os.path.join(user_dir, "media")
|
||||
UPLOAD_FOLDER = os.path.join(APPLICATION_ROOT, "media", "uploads")
|
||||
CACHE_FOLDER = os.path.join(APPLICATION_ROOT, "media", "cache")
|
||||
PFP_FOLDER = os.path.join(APPLICATION_ROOT, "media", "pfp")
|
||||
MEDIA_FOLDER = os.path.join(APPLICATION_ROOT, "media")
|
||||
|
||||
# Database
|
||||
INSTANCE_DIR = instance_dir
|
||||
INSTANCE_DIR = os.path.join(APPLICATION_ROOT, "instance")
|
||||
MIGRATIONS_DIR = os.path.join(INSTANCE_DIR, "migrations")
|
||||
|
||||
# App
|
||||
|
|
|
@ -14,47 +14,6 @@ function imageFullscreen() {
|
|||
}
|
||||
|
||||
function imageShowOptionsPopup(obj) {
|
||||
// let title = 'Options';
|
||||
// let subtitle = null;
|
||||
//
|
||||
// let body = document.createElement('div');
|
||||
// body.style.cssText = 'display: flex; flex-direction: column; gap: 0.5rem;';
|
||||
//
|
||||
// let copyBtn = document.createElement('button');
|
||||
// copyBtn.classList.add('btn-block');
|
||||
// copyBtn.innerHTML = 'Copy URL';
|
||||
// copyBtn.onclick = () => {
|
||||
// copyToClipboard(window.location.href)
|
||||
// }
|
||||
//
|
||||
// let downloadBtn = document.createElement('a');
|
||||
// downloadBtn.classList.add('btn-block');
|
||||
// downloadBtn.innerHTML = 'Download';
|
||||
// downloadBtn.href = '/api/media/uploads/' + image_data["filename"];
|
||||
// downloadBtn.download = '';
|
||||
//
|
||||
// body.appendChild(copyBtn);
|
||||
// body.appendChild(downloadBtn);
|
||||
//
|
||||
// if (image_data["owner"]) {
|
||||
// let editBtn = document.createElement('button');
|
||||
// editBtn.classList.add('btn-block');
|
||||
// editBtn.classList.add('critical');
|
||||
// editBtn.innerHTML = 'Edit';
|
||||
// editBtn.onclick = imageEditPopup;
|
||||
//
|
||||
// let deleteBtn = document.createElement('button');
|
||||
// deleteBtn.classList.add('btn-block');
|
||||
// deleteBtn.classList.add('critical');
|
||||
// deleteBtn.innerHTML = 'Delete';
|
||||
// deleteBtn.onclick = imageDeletePopup;
|
||||
//
|
||||
// body.appendChild(editBtn);
|
||||
// body.appendChild(deleteBtn);
|
||||
// }
|
||||
//
|
||||
// popupShow(title, subtitle, body, [popupCancelButton]);
|
||||
|
||||
showContextMenu(obj, [
|
||||
{
|
||||
'value': 'Edit',
|
||||
|
|
|
@ -141,41 +141,14 @@ function clearUpload() {
|
|||
}
|
||||
|
||||
|
||||
// function createJob(file) {
|
||||
// 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);
|
||||
|
||||
// jobImgFilter = document.createElement("span");
|
||||
// jobImgFilter.classList.add("img-filter");
|
||||
|
||||
// jobContainer.appendChild(jobStatus);
|
||||
// jobContainer.appendChild(jobProgress);
|
||||
// jobContainer.appendChild(jobImg);
|
||||
// jobContainer.appendChild(jobImgFilter);
|
||||
|
||||
// return jobContainer;
|
||||
// }
|
||||
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
// Function to upload images
|
||||
const uploadTab = document.querySelector(".upload-panel");
|
||||
|
||||
if (!uploadTab) { return; } // If upload tab doesn't exist, don't run this code :3
|
||||
if (!uploadTab) { return }
|
||||
|
||||
const uploadTabDrag = uploadTab.querySelector("#dragIndicator");
|
||||
const uploadForm = uploadTab.querySelector('#uploadForm');
|
||||
// let jobList = document.querySelector(".upload-jobs");
|
||||
|
||||
const fileDrop = uploadForm.querySelector('.fileDrop-block');
|
||||
const fileDropTitle = fileDrop.querySelector('.status');
|
||||
|
@ -228,54 +201,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
formData.append("description", fileDescription.value);
|
||||
formData.append("tags", fileTags.value);
|
||||
|
||||
// jobItem = createJob(fileUpload.files[0]);
|
||||
// jobStatus = jobItem.querySelector(".job__status");
|
||||
|
||||
// Upload the information
|
||||
// $.ajax({
|
||||
// url: '/api/upload',
|
||||
// type: 'post',
|
||||
// data: formData,
|
||||
// contentType: false,
|
||||
// processData: false,
|
||||
// beforeSend: function () {
|
||||
// // Add job to list
|
||||
// jobList.appendChild(jobItem);
|
||||
// },
|
||||
// success: function (response) {
|
||||
// jobItem.classList.add("success");
|
||||
// jobStatus.innerHTML = "Uploaded successfully";
|
||||
// if (!document.querySelector(".upload-panel").classList.contains("open")) {
|
||||
// addNotification("Image uploaded successfully", 1);
|
||||
// }
|
||||
// },
|
||||
// error: function (response) {
|
||||
// jobItem.classList.add("critical");
|
||||
// switch (response.status) {
|
||||
// case 500:
|
||||
// jobStatus.innerHTML = "Server exploded, F's in chat";
|
||||
// break;
|
||||
// case 400:
|
||||
// case 404:
|
||||
// jobStatus.innerHTML = "Error uploading. Blame yourself";
|
||||
// break;
|
||||
// case 403:
|
||||
// jobStatus.innerHTML = "None but devils play past here...";
|
||||
// break;
|
||||
// case 413:
|
||||
// jobStatus.innerHTML = "File too large!!!!!!";
|
||||
// break;
|
||||
// default:
|
||||
// jobStatus.innerHTML = "Error uploading file, blame someone";
|
||||
// break;
|
||||
// }
|
||||
// if (!document.querySelector(".upload-panel").classList.contains("open")) {
|
||||
// addNotification("Error uploading file", 2);
|
||||
// }
|
||||
// },
|
||||
// });
|
||||
|
||||
|
||||
fetch('/api/media/upload', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
|
|
|
@ -1,23 +1,15 @@
|
|||
@keyframes notificationTimeout
|
||||
0%
|
||||
left: -100%
|
||||
height: 3px
|
||||
90%
|
||||
left: 0%
|
||||
height: 3px
|
||||
95%
|
||||
left: 0%
|
||||
height: 0
|
||||
width: 0
|
||||
100%
|
||||
left: 0%
|
||||
height: 0
|
||||
width: 100%
|
||||
|
||||
@mixin notification($color)
|
||||
color: RGB($color)
|
||||
|
||||
&::after
|
||||
background-color: RGB($color)
|
||||
|
||||
|
||||
.notifications
|
||||
margin: 0
|
||||
padding: 0
|
||||
|
@ -60,17 +52,17 @@
|
|||
&::after
|
||||
content: ""
|
||||
|
||||
width: 100%
|
||||
width: 0
|
||||
height: 3px
|
||||
|
||||
position: absolute
|
||||
bottom: 0px
|
||||
left: 0px
|
||||
bottom: 0
|
||||
left: 0
|
||||
|
||||
background-color: RGB($fg-white)
|
||||
|
||||
z-index: +2
|
||||
animation: notificationTimeout 5.1s linear
|
||||
animation: notificationTimeout 5.1s ease-out forwards
|
||||
|
||||
&.success
|
||||
@include notification($success)
|
||||
|
@ -89,7 +81,7 @@
|
|||
margin: 0
|
||||
max-height: 0
|
||||
opacity: 0
|
||||
transform: translateX(100%)
|
||||
transform: translateY(1rem)
|
||||
transition: all 0.4s ease-in-out, max-height 0.2s ease-in-out
|
||||
|
||||
.sniffle__notification-icon
|
||||
|
@ -133,10 +125,6 @@
|
|||
|
||||
.sniffle__notification
|
||||
width: 100%
|
||||
|
||||
&.hide
|
||||
opacity: 0
|
||||
transform: translateY(1rem)
|
||||
|
||||
.sniffle__notification-time
|
||||
width: 100%
|
||||
|
|
|
@ -60,16 +60,18 @@ body
|
|||
padding: 0 0 3.5rem 0
|
||||
|
||||
main
|
||||
margin: 0 0.5rem 0.5rem 0
|
||||
display: flex
|
||||
flex-direction: column
|
||||
position: relative
|
||||
background: RGBA($white, 1)
|
||||
color: RGB($fg-black)
|
||||
border-top-left-radius: $rad
|
||||
border-radius: $rad
|
||||
overflow: hidden
|
||||
@media (max-width: $breakpoint)
|
||||
main
|
||||
border-top-left-radius: 0
|
||||
margin: 0
|
||||
border-radius: 0
|
||||
|
||||
.error-page
|
||||
min-height: 100%
|
||||
|
|
156
onlylegs/utils/startup.py
Normal file
156
onlylegs/utils/startup.py
Normal file
|
@ -0,0 +1,156 @@
|
|||
"""
|
||||
OnlyLegs - Setup
|
||||
Runs when the app detects that there is no user directory
|
||||
"""
|
||||
import os
|
||||
import re
|
||||
import platformdirs
|
||||
import yaml
|
||||
from werkzeug.security import generate_password_hash
|
||||
from onlylegs.extensions import db
|
||||
from onlylegs.models import Users
|
||||
|
||||
|
||||
APPLICATION_ROOT = platformdirs.user_config_dir("onlyLegs")
|
||||
REQUIRED_DIRS = {
|
||||
"root": APPLICATION_ROOT,
|
||||
"instance": os.path.join(APPLICATION_ROOT, "instance"),
|
||||
"media": os.path.join(APPLICATION_ROOT, "media"),
|
||||
"uploads": os.path.join(APPLICATION_ROOT, "media", "uploads"),
|
||||
"cache": os.path.join(APPLICATION_ROOT, "media", "cache"),
|
||||
"pfp": os.path.join(APPLICATION_ROOT, "media", "pfp"),
|
||||
}
|
||||
|
||||
EMAIL_REGEX = re.compile(r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b")
|
||||
USERNAME_REGEX = re.compile(r"\b[A-Za-z0-9._%+-]+\b")
|
||||
|
||||
|
||||
def check_dirs():
|
||||
"""
|
||||
Create the user directory
|
||||
"""
|
||||
|
||||
for directory in REQUIRED_DIRS.values():
|
||||
if os.path.exists(directory):
|
||||
print("User directory already exists at:", directory)
|
||||
return
|
||||
os.makedirs(directory)
|
||||
print("Created directory at:", directory)
|
||||
|
||||
|
||||
def check_env():
|
||||
"""
|
||||
Create the .env file with default values
|
||||
"""
|
||||
if os.path.exists(os.path.join(APPLICATION_ROOT, ".env")):
|
||||
print("Environment file already exists at:", APPLICATION_ROOT)
|
||||
return
|
||||
|
||||
env_conf = {
|
||||
"FLASK_SECRET": os.urandom(32).hex(),
|
||||
}
|
||||
|
||||
with open(
|
||||
os.path.join(APPLICATION_ROOT, ".env"), encoding="utf-8", mode="w+"
|
||||
) as file:
|
||||
for key, value in env_conf.items():
|
||||
file.write(key + "=" + value + "\n")
|
||||
|
||||
print(
|
||||
"####################################################"
|
||||
"# A NEW KEY WAS GENERATED FOR YOU! PLEASE NOTE #"
|
||||
"# DOWN THE FLASK_SECRET KEY LOCATED IN YOUR #"
|
||||
"# ~/.config/onlylegs/.env FOLDER! LOOSING THIS KEY #"
|
||||
"# WILL RESULT IN YOU BEING UNABLE TO LOG IN! #"
|
||||
"####################################################",
|
||||
sep="\n",
|
||||
)
|
||||
|
||||
|
||||
def check_conf():
|
||||
"""
|
||||
Create the YAML config file with default values
|
||||
"""
|
||||
if os.path.exists(os.path.join(APPLICATION_ROOT, "conf.yml")):
|
||||
print("Config file already exists at:", APPLICATION_ROOT)
|
||||
return
|
||||
|
||||
can_continue = False
|
||||
username = "admin"
|
||||
name = "Admin"
|
||||
email = "admin@example.com"
|
||||
|
||||
print("No config file found, please enter the following information:")
|
||||
while can_continue:
|
||||
username = input("Admin username: ")
|
||||
name = input("Admin name: ")
|
||||
email = input("Admin email: ")
|
||||
|
||||
if not username or not USERNAME_REGEX.match(username):
|
||||
print("Username is invalid!")
|
||||
if not name:
|
||||
print("Name is invalid!")
|
||||
if not email or not EMAIL_REGEX.match(email):
|
||||
print("Email is invalid!")
|
||||
|
||||
# Check if user is happy with the values
|
||||
is_correct = input("Is this correct? (Y/n): ").lower()
|
||||
if is_correct == "y" or is_correct == "":
|
||||
can_continue = True
|
||||
|
||||
yaml_conf = {
|
||||
"admin": {
|
||||
"name": name,
|
||||
"username": username,
|
||||
"email": email,
|
||||
},
|
||||
"upload": {
|
||||
"allowed-extensions": {
|
||||
"jpg": "jpeg",
|
||||
"jpeg": "jpeg",
|
||||
"png": "png",
|
||||
"webp": "webp",
|
||||
},
|
||||
"max-size": 69,
|
||||
"max-load": 50,
|
||||
"rename": "GWA_{{username}}_{{time}}",
|
||||
},
|
||||
"website": {
|
||||
"name": "OnlyLegs",
|
||||
"motto": "A gallery built for fast and simple image management!",
|
||||
"language": "en",
|
||||
},
|
||||
}
|
||||
|
||||
with open(
|
||||
os.path.join(APPLICATION_ROOT, "conf.yml"), encoding="utf-8", mode="w+"
|
||||
) as file:
|
||||
yaml.dump(yaml_conf, file, default_flow_style=False)
|
||||
|
||||
print(
|
||||
"####################################################"
|
||||
"# A NEW CONFIG HAS BEEN GENERATED AT: #"
|
||||
"# ~/.config/onlylegs/conf.yml #"
|
||||
"####################################################",
|
||||
sep="\n",
|
||||
)
|
||||
|
||||
|
||||
def make_admin_user(app):
|
||||
username = app.config["ADMIN_CONF"]["username"]
|
||||
email = app.config["ADMIN_CONF"]["email"]
|
||||
password = generate_password_hash("changeme!", method="scrypt")
|
||||
|
||||
with app.app_context():
|
||||
db.create_all()
|
||||
db.session.add(Users(username=username, email=email, password=password))
|
||||
db.session.commit()
|
||||
|
||||
print(
|
||||
"####################################################"
|
||||
"# DEFAULT ADMIN USER GENERATED WITH GIVEN USERNAME #"
|
||||
'# THE DEFAULT PASSWORD "changeme!" HAS BEEN USED, #'
|
||||
"# PLEASE RESET IT IN THE SETTINGS! #"
|
||||
"####################################################",
|
||||
sep="\n",
|
||||
)
|
118
poetry.lock
generated
118
poetry.lock
generated
|
@ -1,4 +1,4 @@
|
|||
# This file is automatically @generated by Poetry and should not be changed by hand.
|
||||
# This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "alembic"
|
||||
|
@ -727,6 +727,22 @@ files = [
|
|||
{file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "material-color-utilities-python"
|
||||
version = "0.1.5"
|
||||
description = "Python port of material-color-utilities used for Material You colors"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "material-color-utilities-python-0.1.5.tar.gz", hash = "sha256:3c6f02e7ce70595885447bdef37cf76fd3628c7c95fa2198d8174c269c951fae"},
|
||||
{file = "material_color_utilities_python-0.1.5-py2.py3-none-any.whl", hash = "sha256:48abd8695a1355ab3ad43fe314ca8664c66282a86fbf94a717571273bf422bdf"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
Pillow = ">=9.2.0,<10.0.0"
|
||||
regex = "*"
|
||||
|
||||
[[package]]
|
||||
name = "mccabe"
|
||||
version = "0.7.0"
|
||||
|
@ -966,6 +982,104 @@ files = [
|
|||
{file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "2023.8.8"
|
||||
description = "Alternative regular expression module, to replace re."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "regex-2023.8.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:88900f521c645f784260a8d346e12a1590f79e96403971241e64c3a265c8ecdb"},
|
||||
{file = "regex-2023.8.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3611576aff55918af2697410ff0293d6071b7e00f4b09e005d614686ac4cd57c"},
|
||||
{file = "regex-2023.8.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b8a0ccc8f2698f120e9e5742f4b38dc944c38744d4bdfc427616f3a163dd9de5"},
|
||||
{file = "regex-2023.8.8-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c662a4cbdd6280ee56f841f14620787215a171c4e2d1744c9528bed8f5816c96"},
|
||||
{file = "regex-2023.8.8-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cf0633e4a1b667bfe0bb10b5e53fe0d5f34a6243ea2530eb342491f1adf4f739"},
|
||||
{file = "regex-2023.8.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:551ad543fa19e94943c5b2cebc54c73353ffff08228ee5f3376bd27b3d5b9800"},
|
||||
{file = "regex-2023.8.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54de2619f5ea58474f2ac211ceea6b615af2d7e4306220d4f3fe690c91988a61"},
|
||||
{file = "regex-2023.8.8-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5ec4b3f0aebbbe2fc0134ee30a791af522a92ad9f164858805a77442d7d18570"},
|
||||
{file = "regex-2023.8.8-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3ae646c35cb9f820491760ac62c25b6d6b496757fda2d51be429e0e7b67ae0ab"},
|
||||
{file = "regex-2023.8.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ca339088839582d01654e6f83a637a4b8194d0960477b9769d2ff2cfa0fa36d2"},
|
||||
{file = "regex-2023.8.8-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:d9b6627408021452dcd0d2cdf8da0534e19d93d070bfa8b6b4176f99711e7f90"},
|
||||
{file = "regex-2023.8.8-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:bd3366aceedf274f765a3a4bc95d6cd97b130d1dda524d8f25225d14123c01db"},
|
||||
{file = "regex-2023.8.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7aed90a72fc3654fba9bc4b7f851571dcc368120432ad68b226bd593f3f6c0b7"},
|
||||
{file = "regex-2023.8.8-cp310-cp310-win32.whl", hash = "sha256:80b80b889cb767cc47f31d2b2f3dec2db8126fbcd0cff31b3925b4dc6609dcdb"},
|
||||
{file = "regex-2023.8.8-cp310-cp310-win_amd64.whl", hash = "sha256:b82edc98d107cbc7357da7a5a695901b47d6eb0420e587256ba3ad24b80b7d0b"},
|
||||
{file = "regex-2023.8.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1e7d84d64c84ad97bf06f3c8cb5e48941f135ace28f450d86af6b6512f1c9a71"},
|
||||
{file = "regex-2023.8.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ce0f9fbe7d295f9922c0424a3637b88c6c472b75eafeaff6f910494a1fa719ef"},
|
||||
{file = "regex-2023.8.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06c57e14ac723b04458df5956cfb7e2d9caa6e9d353c0b4c7d5d54fcb1325c46"},
|
||||
{file = "regex-2023.8.8-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e7a9aaa5a1267125eef22cef3b63484c3241aaec6f48949b366d26c7250e0357"},
|
||||
{file = "regex-2023.8.8-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b7408511fca48a82a119d78a77c2f5eb1b22fe88b0d2450ed0756d194fe7a9a"},
|
||||
{file = "regex-2023.8.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14dc6f2d88192a67d708341f3085df6a4f5a0c7b03dec08d763ca2cd86e9f559"},
|
||||
{file = "regex-2023.8.8-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48c640b99213643d141550326f34f0502fedb1798adb3c9eb79650b1ecb2f177"},
|
||||
{file = "regex-2023.8.8-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0085da0f6c6393428bf0d9c08d8b1874d805bb55e17cb1dfa5ddb7cfb11140bf"},
|
||||
{file = "regex-2023.8.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:964b16dcc10c79a4a2be9f1273fcc2684a9eedb3906439720598029a797b46e6"},
|
||||
{file = "regex-2023.8.8-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7ce606c14bb195b0e5108544b540e2c5faed6843367e4ab3deb5c6aa5e681208"},
|
||||
{file = "regex-2023.8.8-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:40f029d73b10fac448c73d6eb33d57b34607f40116e9f6e9f0d32e9229b147d7"},
|
||||
{file = "regex-2023.8.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3b8e6ea6be6d64104d8e9afc34c151926f8182f84e7ac290a93925c0db004bfd"},
|
||||
{file = "regex-2023.8.8-cp311-cp311-win32.whl", hash = "sha256:942f8b1f3b223638b02df7df79140646c03938d488fbfb771824f3d05fc083a8"},
|
||||
{file = "regex-2023.8.8-cp311-cp311-win_amd64.whl", hash = "sha256:51d8ea2a3a1a8fe4f67de21b8b93757005213e8ac3917567872f2865185fa7fb"},
|
||||
{file = "regex-2023.8.8-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e951d1a8e9963ea51efd7f150450803e3b95db5939f994ad3d5edac2b6f6e2b4"},
|
||||
{file = "regex-2023.8.8-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:704f63b774218207b8ccc6c47fcef5340741e5d839d11d606f70af93ee78e4d4"},
|
||||
{file = "regex-2023.8.8-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:22283c769a7b01c8ac355d5be0715bf6929b6267619505e289f792b01304d898"},
|
||||
{file = "regex-2023.8.8-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:91129ff1bb0619bc1f4ad19485718cc623a2dc433dff95baadbf89405c7f6b57"},
|
||||
{file = "regex-2023.8.8-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de35342190deb7b866ad6ba5cbcccb2d22c0487ee0cbb251efef0843d705f0d4"},
|
||||
{file = "regex-2023.8.8-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b993b6f524d1e274a5062488a43e3f9f8764ee9745ccd8e8193df743dbe5ee61"},
|
||||
{file = "regex-2023.8.8-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3026cbcf11d79095a32d9a13bbc572a458727bd5b1ca332df4a79faecd45281c"},
|
||||
{file = "regex-2023.8.8-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:293352710172239bf579c90a9864d0df57340b6fd21272345222fb6371bf82b3"},
|
||||
{file = "regex-2023.8.8-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:d909b5a3fff619dc7e48b6b1bedc2f30ec43033ba7af32f936c10839e81b9217"},
|
||||
{file = "regex-2023.8.8-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:3d370ff652323c5307d9c8e4c62efd1956fb08051b0e9210212bc51168b4ff56"},
|
||||
{file = "regex-2023.8.8-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:b076da1ed19dc37788f6a934c60adf97bd02c7eea461b73730513921a85d4235"},
|
||||
{file = "regex-2023.8.8-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:e9941a4ada58f6218694f382e43fdd256e97615db9da135e77359da257a7168b"},
|
||||
{file = "regex-2023.8.8-cp36-cp36m-win32.whl", hash = "sha256:a8c65c17aed7e15a0c824cdc63a6b104dfc530f6fa8cb6ac51c437af52b481c7"},
|
||||
{file = "regex-2023.8.8-cp36-cp36m-win_amd64.whl", hash = "sha256:aadf28046e77a72f30dcc1ab185639e8de7f4104b8cb5c6dfa5d8ed860e57236"},
|
||||
{file = "regex-2023.8.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:423adfa872b4908843ac3e7a30f957f5d5282944b81ca0a3b8a7ccbbfaa06103"},
|
||||
{file = "regex-2023.8.8-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ae594c66f4a7e1ea67232a0846649a7c94c188d6c071ac0210c3e86a5f92109"},
|
||||
{file = "regex-2023.8.8-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e51c80c168074faa793685656c38eb7a06cbad7774c8cbc3ea05552d615393d8"},
|
||||
{file = "regex-2023.8.8-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:09b7f4c66aa9d1522b06e31a54f15581c37286237208df1345108fcf4e050c18"},
|
||||
{file = "regex-2023.8.8-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e73e5243af12d9cd6a9d6a45a43570dbe2e5b1cdfc862f5ae2b031e44dd95a8"},
|
||||
{file = "regex-2023.8.8-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:941460db8fe3bd613db52f05259c9336f5a47ccae7d7def44cc277184030a116"},
|
||||
{file = "regex-2023.8.8-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f0ccf3e01afeb412a1a9993049cb160d0352dba635bbca7762b2dc722aa5742a"},
|
||||
{file = "regex-2023.8.8-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:2e9216e0d2cdce7dbc9be48cb3eacb962740a09b011a116fd7af8c832ab116ca"},
|
||||
{file = "regex-2023.8.8-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:5cd9cd7170459b9223c5e592ac036e0704bee765706445c353d96f2890e816c8"},
|
||||
{file = "regex-2023.8.8-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:4873ef92e03a4309b3ccd8281454801b291b689f6ad45ef8c3658b6fa761d7ac"},
|
||||
{file = "regex-2023.8.8-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:239c3c2a339d3b3ddd51c2daef10874410917cd2b998f043c13e2084cb191684"},
|
||||
{file = "regex-2023.8.8-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:1005c60ed7037be0d9dea1f9c53cc42f836188227366370867222bda4c3c6bd7"},
|
||||
{file = "regex-2023.8.8-cp37-cp37m-win32.whl", hash = "sha256:e6bd1e9b95bc5614a7a9c9c44fde9539cba1c823b43a9f7bc11266446dd568e3"},
|
||||
{file = "regex-2023.8.8-cp37-cp37m-win_amd64.whl", hash = "sha256:9a96edd79661e93327cfeac4edec72a4046e14550a1d22aa0dd2e3ca52aec921"},
|
||||
{file = "regex-2023.8.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f2181c20ef18747d5f4a7ea513e09ea03bdd50884a11ce46066bb90fe4213675"},
|
||||
{file = "regex-2023.8.8-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a2ad5add903eb7cdde2b7c64aaca405f3957ab34f16594d2b78d53b8b1a6a7d6"},
|
||||
{file = "regex-2023.8.8-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9233ac249b354c54146e392e8a451e465dd2d967fc773690811d3a8c240ac601"},
|
||||
{file = "regex-2023.8.8-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:920974009fb37b20d32afcdf0227a2e707eb83fe418713f7a8b7de038b870d0b"},
|
||||
{file = "regex-2023.8.8-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd2b6c5dfe0929b6c23dde9624483380b170b6e34ed79054ad131b20203a1a63"},
|
||||
{file = "regex-2023.8.8-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96979d753b1dc3b2169003e1854dc67bfc86edf93c01e84757927f810b8c3c93"},
|
||||
{file = "regex-2023.8.8-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ae54a338191e1356253e7883d9d19f8679b6143703086245fb14d1f20196be9"},
|
||||
{file = "regex-2023.8.8-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2162ae2eb8b079622176a81b65d486ba50b888271302190870b8cc488587d280"},
|
||||
{file = "regex-2023.8.8-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c884d1a59e69e03b93cf0dfee8794c63d7de0ee8f7ffb76e5f75be8131b6400a"},
|
||||
{file = "regex-2023.8.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:cf9273e96f3ee2ac89ffcb17627a78f78e7516b08f94dc435844ae72576a276e"},
|
||||
{file = "regex-2023.8.8-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:83215147121e15d5f3a45d99abeed9cf1fe16869d5c233b08c56cdf75f43a504"},
|
||||
{file = "regex-2023.8.8-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:3f7454aa427b8ab9101f3787eb178057c5250478e39b99540cfc2b889c7d0586"},
|
||||
{file = "regex-2023.8.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f0640913d2c1044d97e30d7c41728195fc37e54d190c5385eacb52115127b882"},
|
||||
{file = "regex-2023.8.8-cp38-cp38-win32.whl", hash = "sha256:0c59122ceccb905a941fb23b087b8eafc5290bf983ebcb14d2301febcbe199c7"},
|
||||
{file = "regex-2023.8.8-cp38-cp38-win_amd64.whl", hash = "sha256:c12f6f67495ea05c3d542d119d270007090bad5b843f642d418eb601ec0fa7be"},
|
||||
{file = "regex-2023.8.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:82cd0a69cd28f6cc3789cc6adeb1027f79526b1ab50b1f6062bbc3a0ccb2dbc3"},
|
||||
{file = "regex-2023.8.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:bb34d1605f96a245fc39790a117ac1bac8de84ab7691637b26ab2c5efb8f228c"},
|
||||
{file = "regex-2023.8.8-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:987b9ac04d0b38ef4f89fbc035e84a7efad9cdd5f1e29024f9289182c8d99e09"},
|
||||
{file = "regex-2023.8.8-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9dd6082f4e2aec9b6a0927202c85bc1b09dcab113f97265127c1dc20e2e32495"},
|
||||
{file = "regex-2023.8.8-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7eb95fe8222932c10d4436e7a6f7c99991e3fdd9f36c949eff16a69246dee2dc"},
|
||||
{file = "regex-2023.8.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7098c524ba9f20717a56a8d551d2ed491ea89cbf37e540759ed3b776a4f8d6eb"},
|
||||
{file = "regex-2023.8.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b694430b3f00eb02c594ff5a16db30e054c1b9589a043fe9174584c6efa8033"},
|
||||
{file = "regex-2023.8.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b2aeab3895d778155054abea5238d0eb9a72e9242bd4b43f42fd911ef9a13470"},
|
||||
{file = "regex-2023.8.8-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:988631b9d78b546e284478c2ec15c8a85960e262e247b35ca5eaf7ee22f6050a"},
|
||||
{file = "regex-2023.8.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:67ecd894e56a0c6108ec5ab1d8fa8418ec0cff45844a855966b875d1039a2e34"},
|
||||
{file = "regex-2023.8.8-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:14898830f0a0eb67cae2bbbc787c1a7d6e34ecc06fbd39d3af5fe29a4468e2c9"},
|
||||
{file = "regex-2023.8.8-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:f2200e00b62568cfd920127782c61bc1c546062a879cdc741cfcc6976668dfcf"},
|
||||
{file = "regex-2023.8.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9691a549c19c22d26a4f3b948071e93517bdf86e41b81d8c6ac8a964bb71e5a6"},
|
||||
{file = "regex-2023.8.8-cp39-cp39-win32.whl", hash = "sha256:6ab2ed84bf0137927846b37e882745a827458689eb969028af8032b1b3dac78e"},
|
||||
{file = "regex-2023.8.8-cp39-cp39-win_amd64.whl", hash = "sha256:5543c055d8ec7801901e1193a51570643d6a6ab8751b1f7dd9af71af467538bb"},
|
||||
{file = "regex-2023.8.8.tar.gz", hash = "sha256:fcbdc5f2b0f1cd0f6a56cdb46fe41d2cce1e644e3b68832f3eeebc5fb0f7712e"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "setuptools"
|
||||
version = "68.0.0"
|
||||
|
@ -1232,4 +1346,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p
|
|||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.8"
|
||||
content-hash = "96ec0d1f7b512afb05455262fa2de8c4f862bf68fdae513f8552dc30c6e5ab49"
|
||||
content-hash = "11735dbbdd45dcc5085a04dbbd4e786dd8aeb4ba743f0c20294861e7b4c35dd0"
|
||||
|
|
|
@ -28,6 +28,7 @@ cssmin = "^0.2.0"
|
|||
pylint = "^2.16.3"
|
||||
black = "^23.3.0"
|
||||
cachetools = "^5.3.0"
|
||||
material-color-utilities-python = "^0.1.5"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
"""
|
||||
Startup arguments for the OnlyLegs gallery
|
||||
|
||||
-p, --port: Port to run on (default: 5000)
|
||||
-a, --address: Address to run on (default: 127.0.0.0)
|
||||
-w, --workers: Number of workers to run (default: 4)
|
||||
|
||||
-d, --debug: Run as Flask app in debug mode (default: False)
|
||||
-S, --scream: Show verbose output (default: False)
|
||||
-h, --help: Show a help message
|
||||
"""
|
||||
|
||||
import argparse
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser(description="Run the OnlyLegs gallery")
|
||||
parser.add_argument("-p", "--port", type=int, default=5000, help="Port to run on")
|
||||
parser.add_argument(
|
||||
"-a", "--address", type=str, default="127.0.0.0", help="Address to run on"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-w", "--workers", type=int, default=4, help="Number of workers to run"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-d", "--debug", action="store_true", help="Run as Flask app in debug mode"
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
|
||||
PORT = args.port
|
||||
ADDRESS = args.address
|
||||
WORKERS = args.workers
|
||||
DEBUG = args.debug
|
|
@ -1,156 +0,0 @@
|
|||
"""
|
||||
OnlyLegs - Setup
|
||||
Runs when the app detects that there is no user directory
|
||||
"""
|
||||
import os
|
||||
import logging
|
||||
import re
|
||||
import platformdirs
|
||||
import yaml
|
||||
|
||||
|
||||
USER_DIR = platformdirs.user_config_dir("onlylegs")
|
||||
|
||||
|
||||
class Configuration:
|
||||
"""
|
||||
Setup the application on first run
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
"""
|
||||
Main setup function
|
||||
"""
|
||||
print("Running startup checks...")
|
||||
|
||||
# Check if the user directory exists
|
||||
if not os.path.exists(USER_DIR):
|
||||
self.make_dir()
|
||||
|
||||
# Check if the .env file exists
|
||||
if not os.path.exists(os.path.join(USER_DIR, ".env")):
|
||||
self.make_env()
|
||||
|
||||
# Check if the conf.yml file exists
|
||||
if not os.path.exists(os.path.join(USER_DIR, "conf.yml")):
|
||||
self.make_yaml()
|
||||
|
||||
# Load the config files
|
||||
self.logging_config()
|
||||
|
||||
@staticmethod
|
||||
def make_dir():
|
||||
"""
|
||||
Create the user directory
|
||||
"""
|
||||
os.makedirs(USER_DIR)
|
||||
os.makedirs(os.path.join(USER_DIR, "instance"))
|
||||
os.makedirs(os.path.join(USER_DIR, "media"))
|
||||
os.makedirs(os.path.join(USER_DIR, "media", "uploads"))
|
||||
os.makedirs(os.path.join(USER_DIR, "media", "cache"))
|
||||
os.makedirs(os.path.join(USER_DIR, "media", "pfp"))
|
||||
|
||||
print("Created user directory at:", USER_DIR)
|
||||
|
||||
@staticmethod
|
||||
def make_env():
|
||||
"""
|
||||
Create the .env file with default values
|
||||
"""
|
||||
env_conf = {
|
||||
"FLASK_SECRET": os.urandom(32).hex(),
|
||||
}
|
||||
|
||||
with open(os.path.join(USER_DIR, ".env"), encoding="utf-8", mode="w+") as file:
|
||||
for key, value in env_conf.items():
|
||||
file.write(f"{key}={value}\n")
|
||||
|
||||
print(
|
||||
"""
|
||||
####################################################
|
||||
# A NEW KEY WAS GENERATED FOR YOU! PLEASE NOTE #
|
||||
# DOWN THE FLASK_SECRET KEY LOCATED IN YOUR #
|
||||
# .config/onlylegs/.env FOLDER! LOOSING THIS KEY #
|
||||
# WILL RESULT IN YOU BEING UNABLE TO LOG IN! #
|
||||
####################################################
|
||||
"""
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def make_yaml():
|
||||
"""
|
||||
Create the YAML config file with default values
|
||||
"""
|
||||
is_correct = False
|
||||
email_regex = re.compile(r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b")
|
||||
username_regex = re.compile(r"\b[A-Za-z0-9._%+-]+\b")
|
||||
|
||||
print("\nNo config file found, please enter the following information:")
|
||||
while not is_correct:
|
||||
username = input("Admin username: ")
|
||||
name = input("Admin name: ")
|
||||
email = input("Admin email: ")
|
||||
|
||||
# Check if the values are valid
|
||||
if not username or not username_regex.match(username):
|
||||
print("Username is invalid!")
|
||||
continue
|
||||
|
||||
if not name:
|
||||
print("Name is invalid!")
|
||||
continue
|
||||
|
||||
if not email or not email_regex.match(email):
|
||||
print("Email is invalid!")
|
||||
continue
|
||||
|
||||
# Check if user is happy with the values
|
||||
if input("Is this correct? (y/n): ").lower() == "y":
|
||||
is_correct = True
|
||||
|
||||
yaml_conf = {
|
||||
"admin": {
|
||||
"name": name,
|
||||
"username": username,
|
||||
"email": email,
|
||||
},
|
||||
"upload": {
|
||||
"allowed-extensions": {
|
||||
"jpg": "jpeg",
|
||||
"jpeg": "jpeg",
|
||||
"png": "png",
|
||||
"webp": "webp",
|
||||
},
|
||||
"max-size": 69,
|
||||
"max-load": 50,
|
||||
"rename": "GWA_{{username}}_{{time}}",
|
||||
},
|
||||
"website": {
|
||||
"name": "OnlyLegs",
|
||||
"motto": "A gallery built for fast and simple image management!",
|
||||
"language": "en",
|
||||
},
|
||||
}
|
||||
|
||||
with open(
|
||||
os.path.join(USER_DIR, "conf.yml"), encoding="utf-8", mode="w+"
|
||||
) as file:
|
||||
yaml.dump(yaml_conf, file, default_flow_style=False)
|
||||
|
||||
print(
|
||||
"Generated config file, you can change these values in the settings of the app"
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def logging_config():
|
||||
"""
|
||||
Set the logging config
|
||||
"""
|
||||
logging.getLogger("werkzeug").disabled = True
|
||||
logging.basicConfig(
|
||||
filename=os.path.join(USER_DIR, "only.log"),
|
||||
level=logging.INFO,
|
||||
datefmt="%Y-%m-%d %H:%M:%S",
|
||||
format="%(asctime)s %(levelname)s %(name)s %(threadName)s : %(message)s",
|
||||
encoding="utf-8",
|
||||
)
|
|
@ -1,35 +0,0 @@
|
|||
"""
|
||||
Gunicorn configuration file
|
||||
"""
|
||||
from gunicorn.app.base import Application
|
||||
from gunicorn import util
|
||||
|
||||
|
||||
class OnlyLegs(Application):
|
||||
"""
|
||||
Gunicorn application
|
||||
"""
|
||||
|
||||
# TODO: Make this not shit, thanks
|
||||
def __init__(self, options={}): # skipcq: PYL-W0231 # pylint: disable=W0231
|
||||
self.usage = None
|
||||
self.callable = None
|
||||
self.options = options
|
||||
self.do_load_config()
|
||||
|
||||
def init(self, *args):
|
||||
"""
|
||||
Initialize the application
|
||||
"""
|
||||
cfg = {}
|
||||
for setting, value in self.options.items():
|
||||
if setting.lower() in self.cfg.settings and value is not None:
|
||||
cfg[setting.lower()] = value
|
||||
return cfg
|
||||
|
||||
@staticmethod
|
||||
def prog(): # skipcq: PYL-E0202 # pylint: disable=E0202, C0116
|
||||
return "OnlyLegs"
|
||||
|
||||
def load(self):
|
||||
return util.import_app("onlylegs.app:app")
|
Loading…
Reference in a new issue