mirror of
https://github.com/Dvorinka/swingmusic-extended.git
synced 2026-06-03 20:13:02 +00:00
implement CLI password recovery (hacky :omg:)
+ rewrite migrations logic + rename encode_password to hash_password + update image sizes (add medium size) + rename image endpoints
This commit is contained in:
+1
-1
@@ -27,7 +27,7 @@ client
|
|||||||
logs.txt
|
logs.txt
|
||||||
*.spec
|
*.spec
|
||||||
|
|
||||||
TODO.md
|
# TODO.md
|
||||||
testdata.py
|
testdata.py
|
||||||
test.py
|
test.py
|
||||||
nohup.out
|
nohup.out
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
- Fix migrations!
|
||||||
|
- Use total length instead of release version length
|
||||||
+6
-5
@@ -14,7 +14,7 @@ from flask_openapi3 import Tag
|
|||||||
from flask_openapi3 import APIBlueprint
|
from flask_openapi3 import APIBlueprint
|
||||||
|
|
||||||
from app.db.sqlite.auth import SQLiteAuthMethods as authdb
|
from app.db.sqlite.auth import SQLiteAuthMethods as authdb
|
||||||
from app.utils.auth import check_password, encode_password
|
from app.utils.auth import check_password, hash_password
|
||||||
from app.config import UserConfig
|
from app.config import UserConfig
|
||||||
|
|
||||||
bp_tag = Tag(name="Auth", description="Authentication stuff")
|
bp_tag = Tag(name="Auth", description="Authentication stuff")
|
||||||
@@ -113,7 +113,7 @@ def update_profile(body: UpdateProfileBody):
|
|||||||
user["roles"] = json.dumps(body.roles)
|
user["roles"] = json.dumps(body.roles)
|
||||||
|
|
||||||
if user["password"]:
|
if user["password"]:
|
||||||
user["password"] = encode_password(user["password"])
|
user["password"] = hash_password(user["password"])
|
||||||
|
|
||||||
# remove empty values
|
# remove empty values
|
||||||
clean_user = {k: v for k, v in user.items() if v}
|
clean_user = {k: v for k, v in user.items() if v}
|
||||||
@@ -132,7 +132,7 @@ def create_user(body: UpdateProfileBody):
|
|||||||
|
|
||||||
user = {
|
user = {
|
||||||
"username": body.username,
|
"username": body.username,
|
||||||
"password": encode_password(body.password),
|
"password": hash_password(body.password),
|
||||||
"roles": json.dumps([]),
|
"roles": json.dumps([]),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,7 +232,9 @@ def get_all_users(query: GetAllUsersQuery):
|
|||||||
users = authdb.get_all_users()
|
users = authdb.get_all_users()
|
||||||
|
|
||||||
is_admin = current_user and "admin" in current_user["roles"]
|
is_admin = current_user and "admin" in current_user["roles"]
|
||||||
settings['enableGuest'] = [user for user in users if user.username == "guest"].__len__() > 0
|
settings["enableGuest"] = [
|
||||||
|
user for user in users if user.username == "guest"
|
||||||
|
].__len__() > 0
|
||||||
|
|
||||||
# if user is admin, also return settings
|
# if user is admin, also return settings
|
||||||
if is_admin:
|
if is_admin:
|
||||||
@@ -252,7 +254,6 @@ def get_all_users(query: GetAllUsersQuery):
|
|||||||
):
|
):
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
# remove guest user
|
# remove guest user
|
||||||
# if not settings["enableGuest"]:
|
# if not settings["enableGuest"]:
|
||||||
# users = [user for user in users if user.username != "guest"]
|
# users = [user for user in users if user.username != "guest"]
|
||||||
|
|||||||
+59
-39
@@ -13,6 +13,9 @@ api = APIBlueprint("imgserver", __name__, url_prefix="/img", abp_tags=[bp_tag])
|
|||||||
|
|
||||||
|
|
||||||
def send_fallback_img(filename: str = "default.webp"):
|
def send_fallback_img(filename: str = "default.webp"):
|
||||||
|
"""
|
||||||
|
Returns the fallback image from the assets folder.
|
||||||
|
"""
|
||||||
folder = Paths.get_assets_path()
|
folder = Paths.get_assets_path()
|
||||||
img = Path(folder) / filename
|
img = Path(folder) / filename
|
||||||
|
|
||||||
@@ -22,6 +25,18 @@ def send_fallback_img(filename: str = "default.webp"):
|
|||||||
return send_from_directory(folder, filename)
|
return send_from_directory(folder, filename)
|
||||||
|
|
||||||
|
|
||||||
|
def send_file_or_fallback(folder: str, filename: str, fallback: str = "default.webp"):
|
||||||
|
"""
|
||||||
|
Returns the file from the folder or the fallback image.
|
||||||
|
"""
|
||||||
|
fpath = Path(folder) / filename
|
||||||
|
|
||||||
|
if fpath.exists():
|
||||||
|
return send_from_directory(folder, filename)
|
||||||
|
|
||||||
|
return send_fallback_img(fallback)
|
||||||
|
|
||||||
|
|
||||||
class ImagePath(BaseModel):
|
class ImagePath(BaseModel):
|
||||||
imgpath: str = Field(
|
imgpath: str = Field(
|
||||||
description="The image filename",
|
description="The image filename",
|
||||||
@@ -43,62 +58,72 @@ class ImagePath(BaseModel):
|
|||||||
# return send_fallback_img()
|
# return send_fallback_img()
|
||||||
|
|
||||||
|
|
||||||
@api.get("/t/<imgpath>")
|
# TRACK THUMBNAILS
|
||||||
|
@api.get("/thumbnail/<imgpath>")
|
||||||
def send_lg_thumbnail(path: ImagePath):
|
def send_lg_thumbnail(path: ImagePath):
|
||||||
"""
|
"""
|
||||||
Get large thumbnail (500 x 500)
|
Get large thumbnail (500 x 500)
|
||||||
"""
|
"""
|
||||||
folder = Paths.get_lg_thumb_path()
|
folder = Paths.get_lg_thumb_path()
|
||||||
fpath = Path(folder) / path.imgpath
|
return send_file_or_fallback(folder, path.imgpath)
|
||||||
|
|
||||||
if fpath.exists():
|
|
||||||
return send_from_directory(folder, path.imgpath)
|
|
||||||
|
|
||||||
return send_fallback_img()
|
|
||||||
|
|
||||||
|
|
||||||
@api.get("/t/s/<imgpath>")
|
@api.get("/thumbnail/xsmall/<imgpath>")
|
||||||
|
def send_xsm_thumbnail(path: ImagePath):
|
||||||
|
"""
|
||||||
|
Get extra small thumbnail (64px)
|
||||||
|
"""
|
||||||
|
folder = Paths.get_xsm_thumb_path()
|
||||||
|
return send_file_or_fallback(folder, path.imgpath)
|
||||||
|
|
||||||
|
|
||||||
|
@api.get("/thumbnail/small/<imgpath>")
|
||||||
def send_sm_thumbnail(path: ImagePath):
|
def send_sm_thumbnail(path: ImagePath):
|
||||||
"""
|
"""
|
||||||
Get small thumbnail (64 x 64)
|
Get small thumbnail (96px)
|
||||||
"""
|
"""
|
||||||
folder = Paths.get_sm_thumb_path()
|
folder = Paths.get_sm_thumb_path()
|
||||||
fpath = Path(folder) / path.imgpath
|
return send_file_or_fallback(folder, path.imgpath)
|
||||||
|
|
||||||
if fpath.exists():
|
|
||||||
return send_from_directory(folder, path.imgpath)
|
|
||||||
|
|
||||||
return send_fallback_img()
|
|
||||||
|
|
||||||
|
|
||||||
@api.get("/a/<imgpath>")
|
@api.get("/thumbnail/medium/<imgpath>")
|
||||||
|
def send_md_thumbnail(path: ImagePath):
|
||||||
|
"""
|
||||||
|
Get medium thumbnail (256px)
|
||||||
|
"""
|
||||||
|
folder = Paths.get_md_thumb_path()
|
||||||
|
return send_file_or_fallback(folder, path.imgpath)
|
||||||
|
|
||||||
|
|
||||||
|
# ARTISTS
|
||||||
|
@api.get("/artist/<imgpath>")
|
||||||
def send_lg_artist_image(path: ImagePath):
|
def send_lg_artist_image(path: ImagePath):
|
||||||
"""
|
"""
|
||||||
Get large artist image (500 x 500)
|
Get large artist image (500 x 500)
|
||||||
"""
|
"""
|
||||||
folder = Paths.get_artist_img_lg_path()
|
folder = Paths.get_lg_artist_img_path()
|
||||||
fpath = Path(folder) / path.imgpath
|
return send_file_or_fallback(folder, path.imgpath, "artist.webp")
|
||||||
|
|
||||||
if fpath.exists():
|
|
||||||
return send_from_directory(folder, path.imgpath)
|
|
||||||
|
|
||||||
return send_fallback_img("artist.webp")
|
|
||||||
|
|
||||||
|
|
||||||
@api.get("/a/s/<imgpath>")
|
@api.get("/artist/small/<imgpath>")
|
||||||
def send_sm_artist_image(path: ImagePath):
|
def send_sm_artist_image(path: ImagePath):
|
||||||
"""
|
"""
|
||||||
Get small artist image (64 x 64)
|
Get small artist image (128)
|
||||||
"""
|
"""
|
||||||
folder = Paths.get_artist_img_sm_path()
|
folder = Paths.get_sm_artist_img_path()
|
||||||
fpath = Path(folder) / path.imgpath
|
return send_file_or_fallback(folder, path.imgpath, "artist.webp")
|
||||||
|
|
||||||
if fpath.exists():
|
|
||||||
return send_from_directory(folder, path.imgpath)
|
|
||||||
|
|
||||||
return send_fallback_img("artist.webp")
|
|
||||||
|
|
||||||
|
|
||||||
|
@api.get("/artist/medium/<imgpath>")
|
||||||
|
def send_md_artist_image(path: ImagePath):
|
||||||
|
"""
|
||||||
|
Get medium artist image (256px)
|
||||||
|
"""
|
||||||
|
folder = Paths.get_md_artist_img_path()
|
||||||
|
return send_file_or_fallback(folder, path.imgpath, "artist.webp")
|
||||||
|
|
||||||
|
|
||||||
|
# PLAYLISTS
|
||||||
class PlaylistImagePath(BaseModel):
|
class PlaylistImagePath(BaseModel):
|
||||||
imgpath: str = Field(
|
imgpath: str = Field(
|
||||||
description="The image path",
|
description="The image path",
|
||||||
@@ -106,7 +131,7 @@ class PlaylistImagePath(BaseModel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@api.get("/p/<imgpath>")
|
@api.get("/playlist/<imgpath>")
|
||||||
def send_playlist_image(path: PlaylistImagePath):
|
def send_playlist_image(path: PlaylistImagePath):
|
||||||
"""
|
"""
|
||||||
Get playlist image
|
Get playlist image
|
||||||
@@ -114,9 +139,4 @@ def send_playlist_image(path: PlaylistImagePath):
|
|||||||
Images are constructed as '{playlist_id}.webp'
|
Images are constructed as '{playlist_id}.webp'
|
||||||
"""
|
"""
|
||||||
folder = Paths.get_playlist_img_path()
|
folder = Paths.get_playlist_img_path()
|
||||||
fpath = Path(folder) / path.imgpath
|
return send_file_or_fallback(folder, path.imgpath, "playlist.svg")
|
||||||
|
|
||||||
if fpath.exists():
|
|
||||||
return send_from_directory(folder, path.imgpath)
|
|
||||||
|
|
||||||
return send_fallback_img("playlist.svg")
|
|
||||||
|
|||||||
+2
-1
@@ -26,6 +26,7 @@ api = APIBlueprint("playlists", __name__, url_prefix="/playlists", abp_tags=[tag
|
|||||||
|
|
||||||
PL = SQLitePlaylistMethods
|
PL = SQLitePlaylistMethods
|
||||||
|
|
||||||
|
|
||||||
class SendAllPlaylistsQuery(BaseModel):
|
class SendAllPlaylistsQuery(BaseModel):
|
||||||
no_images: bool = Field(False, description="Whether to include images")
|
no_images: bool = Field(False, description="Whether to include images")
|
||||||
|
|
||||||
@@ -410,7 +411,7 @@ def save_item_as_playlist(body: SavePlaylistAsItemBody):
|
|||||||
filename = itemhash + ".webp"
|
filename = itemhash + ".webp"
|
||||||
|
|
||||||
base_path = (
|
base_path = (
|
||||||
Paths.get_artist_img_lg_path()
|
Paths.get_lg_artist_img_path()
|
||||||
if itemtype == "artist"
|
if itemtype == "artist"
|
||||||
else Paths.get_lg_thumb_path()
|
else Paths.get_lg_thumb_path()
|
||||||
)
|
)
|
||||||
|
|||||||
+55
-8
@@ -2,6 +2,7 @@
|
|||||||
Handles arguments passed to the program.
|
Handles arguments passed to the program.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from getpass import getpass
|
||||||
import os.path
|
import os.path
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
@@ -10,27 +11,37 @@ import PyInstaller.__main__ as bundler
|
|||||||
from app import settings
|
from app import settings
|
||||||
from app.logger import log
|
from app.logger import log
|
||||||
from app.print_help import HELP_MESSAGE
|
from app.print_help import HELP_MESSAGE
|
||||||
|
from app.utils.auth import hash_password
|
||||||
from app.utils.paths import getFlaskOpenApiPath
|
from app.utils.paths import getFlaskOpenApiPath
|
||||||
from app.utils.xdg_utils import get_xdg_config_dir
|
from app.utils.xdg_utils import get_xdg_config_dir
|
||||||
from app.utils.wintools import is_windows
|
from app.utils.wintools import is_windows
|
||||||
|
from app.db.sqlite.auth import SQLiteAuthMethods as authdb
|
||||||
|
|
||||||
ALLARGS = settings.ALLARGS
|
ALLARGS = settings.ALLARGS
|
||||||
ARGS = sys.argv[1:]
|
ARGS = sys.argv[1:]
|
||||||
|
|
||||||
|
|
||||||
class ProcessArgs:
|
class ProcessArgs:
|
||||||
|
"""
|
||||||
|
Processes the arguments passed to the program.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
|
# resolve config path
|
||||||
|
self.handle_config_path() # 1
|
||||||
|
|
||||||
|
# handles that exit
|
||||||
|
self.handle_password_recovery()
|
||||||
self.handle_build()
|
self.handle_build()
|
||||||
self.handle_host()
|
|
||||||
self.handle_port()
|
|
||||||
self.handle_config_path()
|
|
||||||
|
|
||||||
self.handle_periodic_scan()
|
|
||||||
self.handle_periodic_scan_interval()
|
|
||||||
|
|
||||||
self.handle_help()
|
self.handle_help()
|
||||||
self.handle_version()
|
self.handle_version()
|
||||||
|
|
||||||
|
# non-exiting handles
|
||||||
|
self.handle_host()
|
||||||
|
self.handle_port()
|
||||||
|
self.handle_periodic_scan()
|
||||||
|
self.handle_periodic_scan_interval()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def handle_build():
|
def handle_build():
|
||||||
"""
|
"""
|
||||||
@@ -57,12 +68,13 @@ class ProcessArgs:
|
|||||||
value = settings.Info.get(key)
|
value = settings.Info.get(key)
|
||||||
|
|
||||||
if not value:
|
if not value:
|
||||||
log.error(f"WARNING: {key} not set in environment")
|
log.error(f"WARNING: {key} not resolved. Exiting ...")
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
lines.append(f'{key} = "{value}"\n')
|
lines.append(f'{key} = "{value}"\n')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
# write the info to the config file
|
||||||
with open("./app/configs.py", "w", encoding="utf-8") as file:
|
with open("./app/configs.py", "w", encoding="utf-8") as file:
|
||||||
# copy the api keys to the config file
|
# copy the api keys to the config file
|
||||||
file.writelines(lines)
|
file.writelines(lines)
|
||||||
@@ -189,3 +201,38 @@ class ProcessArgs:
|
|||||||
f"COMMIT#: {settings.Info.GIT_CURRENT_BRANCH}/{settings.Info.GIT_LATEST_COMMIT_HASH}"
|
f"COMMIT#: {settings.Info.GIT_CURRENT_BRANCH}/{settings.Info.GIT_LATEST_COMMIT_HASH}"
|
||||||
)
|
)
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def handle_password_recovery():
|
||||||
|
if ALLARGS.pswd in ARGS:
|
||||||
|
print("SWING MUSIC v2.0.0 ")
|
||||||
|
print("PASSWORD RECOVERY \n")
|
||||||
|
|
||||||
|
username: str = ""
|
||||||
|
password: str = ""
|
||||||
|
|
||||||
|
# collect username
|
||||||
|
try:
|
||||||
|
username = input("Enter username: ")
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("\nOperation cancelled! Exiting ...")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
username = username.strip()
|
||||||
|
user = authdb.get_user_by_username(username)
|
||||||
|
|
||||||
|
if not user:
|
||||||
|
print(f"User {username} not found")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
# collect password
|
||||||
|
try:
|
||||||
|
password = getpass("Enter new password: ")
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("\nOperation cancelled! Exiting ...")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
password = hash_password(password)
|
||||||
|
user = authdb.update_user({"id": user.id, "password": password})
|
||||||
|
|
||||||
|
sys.exit(0)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import json
|
import json
|
||||||
from app.models.user import User
|
from app.models.user import User
|
||||||
from app.utils.auth import encode_password
|
from app.utils.auth import hash_password
|
||||||
from app.db.sqlite.utils import SQLiteManager
|
from app.db.sqlite.utils import SQLiteManager
|
||||||
|
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ class SQLiteAuthMethods:
|
|||||||
"""
|
"""
|
||||||
user = {
|
user = {
|
||||||
"username": "admin",
|
"username": "admin",
|
||||||
"password": encode_password("admin"),
|
"password": hash_password("admin"),
|
||||||
"roles": json.dumps(["admin"]),
|
"roles": json.dumps(["admin"]),
|
||||||
}
|
}
|
||||||
return SQLiteAuthMethods.insert_user(user)
|
return SQLiteAuthMethods.insert_user(user)
|
||||||
@@ -56,7 +56,7 @@ class SQLiteAuthMethods:
|
|||||||
"""
|
"""
|
||||||
user = {
|
user = {
|
||||||
"username": "guest",
|
"username": "guest",
|
||||||
"password": encode_password("guest"),
|
"password": hash_password("guest"),
|
||||||
"roles": json.dumps(["guest"]),
|
"roles": json.dumps(["guest"]),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ class SQLiteAuthMethods:
|
|||||||
"""
|
"""
|
||||||
Update a user in the database.
|
Update a user in the database.
|
||||||
|
|
||||||
:param user: A dict with the username, password and roles.
|
:param user: A dict with the user id and the fields to update. Ommited fields will not be updated.
|
||||||
"""
|
"""
|
||||||
# get all user dict keys
|
# get all user dict keys
|
||||||
keys = list(user.keys())
|
keys = list(user.keys())
|
||||||
@@ -75,6 +75,7 @@ class SQLiteAuthMethods:
|
|||||||
{', '.join([f"{key} = :{key}" for key in keys if key != 'id'])}
|
{', '.join([f"{key} = :{key}" for key in keys if key != 'id'])}
|
||||||
WHERE id = :id
|
WHERE id = :id
|
||||||
"""
|
"""
|
||||||
|
print(sql, user)
|
||||||
|
|
||||||
with SQLiteManager(userdata_db=True) as cur:
|
with SQLiteManager(userdata_db=True) as cur:
|
||||||
cur.execute(sql, user)
|
cur.execute(sql, user)
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ from app.db.sqlite.utils import SQLiteManager
|
|||||||
|
|
||||||
class MigrationManager:
|
class MigrationManager:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_version() -> int:
|
def get_index() -> int:
|
||||||
"""
|
"""
|
||||||
Returns the latest userdata database version.
|
Returns the latest databases migrations index.
|
||||||
"""
|
"""
|
||||||
sql = "SELECT * FROM dbmigrations"
|
sql = "SELECT * FROM dbmigrations"
|
||||||
with SQLiteManager() as cur:
|
with SQLiteManager() as cur:
|
||||||
@@ -21,9 +21,9 @@ class MigrationManager:
|
|||||||
|
|
||||||
# 👇 Setters 👇
|
# 👇 Setters 👇
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def set_version(version: int):
|
def set_index(version: int):
|
||||||
"""
|
"""
|
||||||
Sets the userdata pre-init database version.
|
Updates the databases migrations index.
|
||||||
"""
|
"""
|
||||||
sql = "UPDATE dbmigrations SET version = ? WHERE id = 1"
|
sql = "UPDATE dbmigrations SET version = ? WHERE id = 1"
|
||||||
with SQLiteManager() as cur:
|
with SQLiteManager() as cur:
|
||||||
|
|||||||
+27
-11
@@ -55,13 +55,22 @@ def get_artist_image_link(artist: str):
|
|||||||
# TODO: Move network calls to utils/network.py
|
# TODO: Move network calls to utils/network.py
|
||||||
class DownloadImage:
|
class DownloadImage:
|
||||||
def __init__(self, url: str, name: str) -> None:
|
def __init__(self, url: str, name: str) -> None:
|
||||||
sm_path = Path(settings.Paths.get_artist_img_sm_path()) / name
|
|
||||||
lg_path = Path(settings.Paths.get_artist_img_lg_path()) / name
|
|
||||||
|
|
||||||
img = self.download(url)
|
img = self.download(url)
|
||||||
|
|
||||||
if img is not None:
|
if img is None:
|
||||||
self.save_img(img, sm_path, lg_path)
|
return
|
||||||
|
|
||||||
|
sm_path = Path(settings.Paths.get_sm_artist_img_path()) / name
|
||||||
|
lg_path = Path(settings.Paths.get_lg_artist_img_path()) / name
|
||||||
|
md_path = Path(settings.Paths.get_md_artist_img_path()) / name
|
||||||
|
|
||||||
|
entries = [
|
||||||
|
(lg_path, None), # save in the original size
|
||||||
|
(sm_path, settings.Defaults.SM_ARTIST_IMG_SIZE),
|
||||||
|
(md_path, settings.Defaults.MD_ARTIST_IMG_SIZE),
|
||||||
|
]
|
||||||
|
|
||||||
|
self.save_img(img, entries)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def download(url: str) -> Image.Image | None:
|
def download(url: str) -> Image.Image | None:
|
||||||
@@ -74,14 +83,21 @@ class DownloadImage:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def save_img(img: Image.Image, sm_path: Path, lg_path: Path):
|
def save_img(img: Image.Image, entries: list[tuple[Path, int | None]]):
|
||||||
"""
|
"""
|
||||||
Saves the image to the destinations.
|
Saves the image to the destinations.
|
||||||
"""
|
"""
|
||||||
img.save(lg_path, format="webp")
|
ratio = img.width / img.height
|
||||||
|
for entry in entries:
|
||||||
|
path, size = entry
|
||||||
|
|
||||||
sm_size = settings.Defaults.SM_ARTIST_IMG_SIZE
|
if size is None:
|
||||||
img.resize((sm_size, sm_size), Image.ANTIALIAS).save(sm_path, format="webp")
|
img.save(path, format="webp")
|
||||||
|
continue
|
||||||
|
|
||||||
|
img.resize((size, int(size / ratio)), Image.ANTIALIAS).save(
|
||||||
|
path, format="webp"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class CheckArtistImages:
|
class CheckArtistImages:
|
||||||
@@ -90,7 +106,7 @@ class CheckArtistImages:
|
|||||||
CHECK_ARTIST_IMAGES_KEY = instance_key
|
CHECK_ARTIST_IMAGES_KEY = instance_key
|
||||||
|
|
||||||
# read all files in the artist image folder
|
# read all files in the artist image folder
|
||||||
path = settings.Paths.get_artist_img_sm_path()
|
path = settings.Paths.get_sm_artist_img_path()
|
||||||
processed = "".join(os.listdir(path)).replace("webp", "")
|
processed = "".join(os.listdir(path)).replace("webp", "")
|
||||||
|
|
||||||
# filter out artists that already have an image
|
# filter out artists that already have an image
|
||||||
@@ -126,7 +142,7 @@ class CheckArtistImages:
|
|||||||
return
|
return
|
||||||
|
|
||||||
img_path = (
|
img_path = (
|
||||||
Path(settings.Paths.get_artist_img_sm_path()) / f"{artist.artisthash}.webp"
|
Path(settings.Paths.get_sm_artist_img_path()) / f"{artist.artisthash}.webp"
|
||||||
)
|
)
|
||||||
|
|
||||||
if img_path.exists():
|
if img_path.exists():
|
||||||
|
|||||||
+1
-1
@@ -42,7 +42,7 @@ def process_color(item_hash: str, is_album=True):
|
|||||||
path = (
|
path = (
|
||||||
settings.Paths.get_sm_thumb_path()
|
settings.Paths.get_sm_thumb_path()
|
||||||
if is_album
|
if is_album
|
||||||
else settings.Paths.get_artist_img_sm_path()
|
else settings.Paths.get_sm_artist_img_path()
|
||||||
)
|
)
|
||||||
path = Path(path) / (item_hash + ".webp")
|
path = Path(path) / (item_hash + ".webp")
|
||||||
|
|
||||||
|
|||||||
+10
-8
@@ -33,20 +33,22 @@ def extract_thumb(filepath: str, webp_path: str, overwrite=False) -> bool:
|
|||||||
"""
|
"""
|
||||||
lg_img_path = os.path.join(Paths.get_lg_thumb_path(), webp_path)
|
lg_img_path = os.path.join(Paths.get_lg_thumb_path(), webp_path)
|
||||||
sm_img_path = os.path.join(Paths.get_sm_thumb_path(), webp_path)
|
sm_img_path = os.path.join(Paths.get_sm_thumb_path(), webp_path)
|
||||||
|
xms_img_path = os.path.join(Paths.get_xsm_thumb_path(), webp_path)
|
||||||
|
md_img_path = os.path.join(Paths.get_md_thumb_path(), webp_path)
|
||||||
|
|
||||||
tsize = Defaults.THUMB_SIZE
|
images = [
|
||||||
sm_tsize = Defaults.SM_THUMB_SIZE
|
(lg_img_path, Defaults.LG_THUMB_SIZE),
|
||||||
|
(sm_img_path, Defaults.SM_THUMB_SIZE),
|
||||||
|
(xms_img_path, Defaults.XSM_THUMB_SIZE),
|
||||||
|
(md_img_path, Defaults.MD_THUMB_SIZE),
|
||||||
|
]
|
||||||
|
|
||||||
def save_image(img: Image.Image):
|
def save_image(img: Image.Image):
|
||||||
width, height = img.size
|
width, height = img.size
|
||||||
ratio = width / height
|
ratio = width / height
|
||||||
|
|
||||||
img.resize((tsize, int(tsize / ratio)), Image.ANTIALIAS).save(
|
for path, size in images:
|
||||||
lg_img_path, "webp"
|
img.resize((size, int(size / ratio)), Image.ANTIALIAS).save(path, "webp")
|
||||||
)
|
|
||||||
img.resize((sm_tsize, int(sm_tsize / ratio)), Image.ANTIALIAS).save(
|
|
||||||
sm_img_path, "webp"
|
|
||||||
)
|
|
||||||
|
|
||||||
if not overwrite and os.path.exists(sm_img_path):
|
if not overwrite and os.path.exists(sm_img_path):
|
||||||
img_size = os.path.getsize(sm_img_path)
|
img_size = os.path.getsize(sm_img_path)
|
||||||
|
|||||||
+26
-21
@@ -2,12 +2,6 @@
|
|||||||
Migrations module.
|
Migrations module.
|
||||||
|
|
||||||
Reads and applies the latest database migrations.
|
Reads and applies the latest database migrations.
|
||||||
|
|
||||||
PLEASE NOTE: OLDER MIGRATIONS CAN NEVER BE DELETED.
|
|
||||||
ONLY MODIFY OLD MIGRATIONS FOR BUG FIXES OR ENHANCEMENTS ONLY
|
|
||||||
[TRY NOT TO MODIFY BEHAVIOR, UNLESS YOU KNOW WHAT YOU'RE DOING].
|
|
||||||
|
|
||||||
PS: Fuck that! Do what you want.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from app.db.sqlite.migrations import MigrationManager
|
from app.db.sqlite.migrations import MigrationManager
|
||||||
@@ -33,21 +27,32 @@ migrations: list[list[Migration]] = [
|
|||||||
def apply_migrations():
|
def apply_migrations():
|
||||||
"""
|
"""
|
||||||
Applies the latest database migrations.
|
Applies the latest database migrations.
|
||||||
|
|
||||||
|
The length of all the migrations is stored in the database
|
||||||
|
and used to check for new migrations. When the length of the
|
||||||
|
migrations list is larger than the number stored in the db,
|
||||||
|
migrations past that index are applied and the new length
|
||||||
|
is stored as the new migration index.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
version = MigrationManager.get_version()
|
index = MigrationManager.get_index()
|
||||||
|
all_migrations = [migration for sublist in migrations for migration in sublist]
|
||||||
|
|
||||||
if version != len(migrations):
|
to_apply: list[Migration] = []
|
||||||
# INFO: Apply new migrations
|
|
||||||
for migration in migrations[version:]:
|
# if index is from old release,
|
||||||
for m in migration:
|
# get migrations from the "migrations" list
|
||||||
try:
|
if index < 3:
|
||||||
m.migrate()
|
_migrations = migrations[index:]
|
||||||
log.info("Applied migration: %s", m.__name__)
|
to_apply = [migration for sublist in _migrations for migration in sublist]
|
||||||
except:
|
else:
|
||||||
log.error("Failed to run migration: %s", m.__name__)
|
to_apply = all_migrations[index:]
|
||||||
|
|
||||||
print("Migrations applied successfully.")
|
for migration in to_apply:
|
||||||
print("Current migration version: ", len(migrations))
|
try:
|
||||||
# bump migration version
|
migration.migrate()
|
||||||
MigrationManager.set_version(len(migrations))
|
log.info("Applied migration: %s", migration.__name__)
|
||||||
|
except:
|
||||||
|
log.error("Failed to run migration: %s", migration.__name__)
|
||||||
|
|
||||||
|
MigrationManager.set_index(len(all_migrations))
|
||||||
|
|||||||
@@ -58,3 +58,19 @@ class DeleteOriginalThumbnails(Migration):
|
|||||||
|
|
||||||
if os.path.exists(og_imgpath):
|
if os.path.exists(og_imgpath):
|
||||||
shutil.rmtree(og_imgpath)
|
shutil.rmtree(og_imgpath)
|
||||||
|
|
||||||
|
class DeleteOriginalThumbnailsa(Migration):
|
||||||
|
"""
|
||||||
|
Original thumbnails are too large and are not needed.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# TODO: Implement this migration
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def migrate():
|
||||||
|
imgpath = Paths.get_thumbs_path()
|
||||||
|
og_imgpath = os.path.join(imgpath, "original")
|
||||||
|
|
||||||
|
if os.path.exists(og_imgpath):
|
||||||
|
shutil.rmtree(og_imgpath)
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,12 @@ from app.logger import log
|
|||||||
def run_periodic_scans():
|
def run_periodic_scans():
|
||||||
"""
|
"""
|
||||||
Runs periodic scans.
|
Runs periodic scans.
|
||||||
|
|
||||||
|
Periodic scans are checks that run every few minutes
|
||||||
|
in the background to do stuff like:
|
||||||
|
- checking for new music
|
||||||
|
- delete deleted entries
|
||||||
|
- downloading artist images, and other data.
|
||||||
"""
|
"""
|
||||||
# ValidateAlbumThumbs()
|
# ValidateAlbumThumbs()
|
||||||
# ValidatePlaylistThumbs()
|
# ValidatePlaylistThumbs()
|
||||||
|
|||||||
+8
-5
@@ -1,4 +1,4 @@
|
|||||||
from app.settings import ALLARGS
|
from app.settings import ALLARGS, Info
|
||||||
from tabulate import tabulate
|
from tabulate import tabulate
|
||||||
|
|
||||||
args = ALLARGS
|
args = ALLARGS
|
||||||
@@ -10,6 +10,7 @@ help_args_list = [
|
|||||||
["--port", "", "Set the port"],
|
["--port", "", "Set the port"],
|
||||||
["--config", "", "Set the config path"],
|
["--config", "", "Set the config path"],
|
||||||
["--no-periodic-scan", "-nps", "Disable periodic scan"],
|
["--no-periodic-scan", "-nps", "Disable periodic scan"],
|
||||||
|
["--pswd", "", "Recover a password"],
|
||||||
[
|
[
|
||||||
"--scan-interval",
|
"--scan-interval",
|
||||||
"-psi",
|
"-psi",
|
||||||
@@ -23,10 +24,12 @@ help_args_list = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
HELP_MESSAGE = f"""
|
HELP_MESSAGE = f"""
|
||||||
Swing Music is a beautiful, self-hosted music player for your
|
Swing Music v{Info.SWINGMUSIC_APP_VERSION}
|
||||||
local audio files. Like a cooler Spotify ... but bring your own music.
|
|
||||||
|
|
||||||
Usage: swingmusic [options] [args]
|
A beautiful, self-hosted music player for your local audio files.
|
||||||
|
Like Spotify ... but bring your own music.
|
||||||
|
|
||||||
{tabulate(help_args_list, headers=["Option", "Short", "Description"], tablefmt="simple_grid", maxcolwidths=[None, None, 40])}
|
Usage: ./swingmusic [options] [args]
|
||||||
|
|
||||||
|
{tabulate(help_args_list, headers=["Option", "Alias", "Description"], tablefmt="psql", maxcolwidths=[None, None, 40])}
|
||||||
"""
|
"""
|
||||||
|
|||||||
+41
-17
@@ -45,22 +45,24 @@ class Paths:
|
|||||||
def get_img_path(cls):
|
def get_img_path(cls):
|
||||||
return join(cls.get_app_dir(), "images")
|
return join(cls.get_app_dir(), "images")
|
||||||
|
|
||||||
|
# ARTISTS
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_artist_img_path(cls):
|
def get_artist_img_path(cls):
|
||||||
return join(cls.get_img_path(), "artists")
|
return join(cls.get_img_path(), "artists")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_artist_img_sm_path(cls):
|
def get_sm_artist_img_path(cls):
|
||||||
return join(cls.get_artist_img_path(), "small")
|
return join(cls.get_artist_img_path(), "small")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_artist_img_lg_path(cls):
|
def get_md_artist_img_path(cls):
|
||||||
return join(cls.get_artist_img_path(), "large")
|
return join(cls.get_artist_img_path(), "medium")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_playlist_img_path(cls):
|
def get_lg_artist_img_path(cls):
|
||||||
return join(cls.get_img_path(), "playlists")
|
return join(cls.get_artist_img_path(), "large")
|
||||||
|
|
||||||
|
# TRACK THUMBNAILS
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_thumbs_path(cls):
|
def get_thumbs_path(cls):
|
||||||
return join(cls.get_img_path(), "thumbnails")
|
return join(cls.get_img_path(), "thumbnails")
|
||||||
@@ -69,10 +71,23 @@ class Paths:
|
|||||||
def get_sm_thumb_path(cls):
|
def get_sm_thumb_path(cls):
|
||||||
return join(cls.get_thumbs_path(), "small")
|
return join(cls.get_thumbs_path(), "small")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_xsm_thumb_path(cls):
|
||||||
|
return join(cls.get_thumbs_path(), "xsmall")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_md_thumb_path(cls):
|
||||||
|
return join(cls.get_thumbs_path(), "medium")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_lg_thumb_path(cls):
|
def get_lg_thumb_path(cls):
|
||||||
return join(cls.get_thumbs_path(), "large")
|
return join(cls.get_thumbs_path(), "large")
|
||||||
|
|
||||||
|
# OTHERS
|
||||||
|
@classmethod
|
||||||
|
def get_playlist_img_path(cls):
|
||||||
|
return join(cls.get_img_path(), "playlists")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_assets_path(cls):
|
def get_assets_path(cls):
|
||||||
return join(Paths.get_app_dir(), "assets")
|
return join(Paths.get_app_dir(), "assets")
|
||||||
@@ -92,12 +107,25 @@ class Paths:
|
|||||||
|
|
||||||
# defaults
|
# defaults
|
||||||
class Defaults:
|
class Defaults:
|
||||||
THUMB_SIZE = 512
|
"""
|
||||||
SM_THUMB_SIZE = 128
|
Contains default values for various settings.
|
||||||
|
|
||||||
|
XSM_THUMB_SIZE: extra small thumbnail size for web client tracklist
|
||||||
|
SM_THUMB_SIZE: small thumbnail size for android client tracklist
|
||||||
|
MD_THUMB_SIZE: medium thumbnail size for web client album cards
|
||||||
|
LG_THUMB_SIZE: large thumbnail size for web client now playing album art
|
||||||
|
|
||||||
|
NOTE: LG_ARTIST_IMG_SIZE is not defined as the images are saved in the original size (500px)
|
||||||
|
"""
|
||||||
|
|
||||||
|
XSM_THUMB_SIZE = 64
|
||||||
|
SM_THUMB_SIZE = 96
|
||||||
|
MD_THUMB_SIZE = 256
|
||||||
|
LG_THUMB_SIZE = 512
|
||||||
|
|
||||||
SM_ARTIST_IMG_SIZE = 128
|
SM_ARTIST_IMG_SIZE = 128
|
||||||
"""
|
MD_ARTIST_IMG_SIZE = 256
|
||||||
The size of extracted images in pixels
|
|
||||||
"""
|
|
||||||
HASH_LENGTH = 10
|
HASH_LENGTH = 10
|
||||||
API_ALBUMHASH = "bfe300e966"
|
API_ALBUMHASH = "bfe300e966"
|
||||||
API_ARTISTHASH = "cae59f1fc5"
|
API_ARTISTHASH = "cae59f1fc5"
|
||||||
@@ -105,7 +133,6 @@ class Defaults:
|
|||||||
API_ALBUMNAME = "The Goat"
|
API_ALBUMNAME = "The Goat"
|
||||||
API_ARTISTNAME = "Polo G"
|
API_ARTISTNAME = "Polo G"
|
||||||
API_TRACKNAME = "Martin & Gina"
|
API_TRACKNAME = "Martin & Gina"
|
||||||
|
|
||||||
API_CARD_LIMIT = 6
|
API_CARD_LIMIT = 6
|
||||||
|
|
||||||
|
|
||||||
@@ -162,6 +189,8 @@ class ALLARGS:
|
|||||||
host = "--host"
|
host = "--host"
|
||||||
config = "--config"
|
config = "--config"
|
||||||
|
|
||||||
|
pswd = "--pswd"
|
||||||
|
|
||||||
show_feat = ("--show-feat", "-sf")
|
show_feat = ("--show-feat", "-sf")
|
||||||
show_prod = ("--show-prod", "-sp")
|
show_prod = ("--show-prod", "-sp")
|
||||||
dont_clean_albums = ("--no-clean-albums", "-nca")
|
dont_clean_albums = ("--no-clean-albums", "-nca")
|
||||||
@@ -275,6 +304,7 @@ class Info:
|
|||||||
NOTE: This class initially written to load keys when running in build mode.
|
NOTE: This class initially written to load keys when running in build mode.
|
||||||
TODO: Remove this class entirely, and implement functionality where needed.
|
TODO: Remove this class entirely, and implement functionality where needed.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
SWINGMUSIC_APP_VERSION = os.environ.get("SWINGMUSIC_APP_VERSION")
|
SWINGMUSIC_APP_VERSION = os.environ.get("SWINGMUSIC_APP_VERSION")
|
||||||
GIT_LATEST_COMMIT_HASH = "<unset>"
|
GIT_LATEST_COMMIT_HASH = "<unset>"
|
||||||
GIT_CURRENT_BRANCH = "<unset>"
|
GIT_CURRENT_BRANCH = "<unset>"
|
||||||
@@ -289,12 +319,6 @@ class Info:
|
|||||||
cls.GIT_LATEST_COMMIT_HASH = getLatestCommitHash()
|
cls.GIT_LATEST_COMMIT_HASH = getLatestCommitHash()
|
||||||
cls.GIT_CURRENT_BRANCH = getCurrentBranch()
|
cls.GIT_CURRENT_BRANCH = getCurrentBranch()
|
||||||
|
|
||||||
cls.verify_keys()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def verify_keys(cls):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get(cls, key: str):
|
def get(cls, key: str):
|
||||||
return getattr(cls, key, None)
|
return getattr(cls, key, None)
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ from app.config import UserConfig
|
|||||||
|
|
||||||
|
|
||||||
def run_setup():
|
def run_setup():
|
||||||
|
"""
|
||||||
|
Creates the config directory, runs migrations, and loads settings.
|
||||||
|
"""
|
||||||
create_config_dir()
|
create_config_dir()
|
||||||
|
|
||||||
# setup config file
|
# setup config file
|
||||||
@@ -32,6 +35,11 @@ def run_setup():
|
|||||||
# settings table is empty
|
# settings table is empty
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def load_into_mem():
|
||||||
|
"""
|
||||||
|
Load all tracks, albums, and artists into memory.
|
||||||
|
"""
|
||||||
instance_key = get_random_str()
|
instance_key = get_random_str()
|
||||||
|
|
||||||
# INFO: Load all tracks, albums, and artists into memory
|
# INFO: Load all tracks, albums, and artists into memory
|
||||||
|
|||||||
+16
-14
@@ -51,28 +51,28 @@ def create_config_dir() -> None:
|
|||||||
"""
|
"""
|
||||||
Creates the config directory if it doesn't exist.
|
Creates the config directory if it doesn't exist.
|
||||||
"""
|
"""
|
||||||
thumb_path = os.path.join("images", "thumbnails")
|
sm_thumb_path = settings.Paths.get_sm_thumb_path()
|
||||||
small_thumb_path = os.path.join(thumb_path, "small")
|
lg_thumb_path = settings.Paths.get_lg_thumb_path()
|
||||||
large_thumb_path = os.path.join(thumb_path, "large")
|
md_thumb_path = settings.Paths.get_md_thumb_path()
|
||||||
|
xsm_thumb_path = settings.Paths.get_xsm_thumb_path()
|
||||||
|
|
||||||
artist_img_path = os.path.join("images", "artists")
|
small_artist_img_path = settings.Paths.get_sm_artist_img_path()
|
||||||
small_artist_img_path = os.path.join(artist_img_path, "small")
|
md_artist_img_path = settings.Paths.get_md_artist_img_path()
|
||||||
large_artist_img_path = os.path.join(artist_img_path, "large")
|
large_artist_img_path = settings.Paths.get_lg_artist_img_path()
|
||||||
|
|
||||||
playlist_img_path = os.path.join("images", "playlists")
|
playlist_img_path = os.path.join("images", "playlists")
|
||||||
|
|
||||||
dirs = [
|
dirs = [
|
||||||
"", # creates the config folder
|
"", # creates the config folder
|
||||||
"images",
|
sm_thumb_path,
|
||||||
"plugins",
|
lg_thumb_path,
|
||||||
|
md_thumb_path,
|
||||||
|
xsm_thumb_path,
|
||||||
"plugins/lyrics",
|
"plugins/lyrics",
|
||||||
thumb_path,
|
playlist_img_path,
|
||||||
small_thumb_path,
|
md_artist_img_path,
|
||||||
large_thumb_path,
|
|
||||||
artist_img_path,
|
|
||||||
small_artist_img_path,
|
small_artist_img_path,
|
||||||
large_artist_img_path,
|
large_artist_img_path,
|
||||||
playlist_img_path,
|
|
||||||
]
|
]
|
||||||
|
|
||||||
for _dir in dirs:
|
for _dir in dirs:
|
||||||
@@ -80,7 +80,9 @@ def create_config_dir() -> None:
|
|||||||
exists = os.path.exists(path)
|
exists = os.path.exists(path)
|
||||||
|
|
||||||
if not exists:
|
if not exists:
|
||||||
os.makedirs(path)
|
# exist_ok=True to create parent directories if they don't exist
|
||||||
|
os.makedirs(path, exist_ok=True)
|
||||||
os.chmod(path, 0o755)
|
os.chmod(path, 0o755)
|
||||||
|
|
||||||
|
# copy assets to the app directory
|
||||||
CopyFiles()
|
CopyFiles()
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ def log_startup_info():
|
|||||||
# os.system("cls" if os.name == "nt" else "echo -e \\\\033c")
|
# os.system("cls" if os.name == "nt" else "echo -e \\\\033c")
|
||||||
|
|
||||||
print(lines)
|
print(lines)
|
||||||
print(f"{TCOLOR.HEADER}SwingMusic {Info.SWINGMUSIC_APP_VERSION} {TCOLOR.ENDC}")
|
print(f"{TCOLOR.HEADER}Swing Music v{Info.SWINGMUSIC_APP_VERSION} {TCOLOR.ENDC}")
|
||||||
|
|
||||||
adresses = [FLASKVARS.get_flask_host()]
|
adresses = [FLASKVARS.get_flask_host()]
|
||||||
|
|
||||||
|
|||||||
+8
-8
@@ -4,13 +4,13 @@ import hashlib
|
|||||||
from app.config import UserConfig
|
from app.config import UserConfig
|
||||||
|
|
||||||
|
|
||||||
def encode_password(password: str) -> str:
|
def hash_password(password: str) -> str:
|
||||||
"""
|
"""
|
||||||
This function encodes the given password.
|
Hashes the given password using sha256 algorithm and the user id as salt.
|
||||||
|
|
||||||
:param password: The password to encode.
|
:param password: The password to hash.
|
||||||
|
|
||||||
:return: The encoded password.
|
:return: The hashed password.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return hashlib.pbkdf2_hmac(
|
return hashlib.pbkdf2_hmac(
|
||||||
@@ -18,14 +18,14 @@ def encode_password(password: str) -> str:
|
|||||||
).hex()
|
).hex()
|
||||||
|
|
||||||
|
|
||||||
def check_password(password: str, encoded: str) -> bool:
|
def check_password(password: str, hashed: str) -> bool:
|
||||||
"""
|
"""
|
||||||
This function checks if the given password matches the encoded password.
|
This function checks if the given password matches the hashed password.
|
||||||
|
|
||||||
:param password: The password to check.
|
:param password: The password to check.
|
||||||
:param encoded: The encoded password.
|
:param hashed: The hashed password.
|
||||||
|
|
||||||
:return: Whether the password matches.
|
:return: Whether the password matches.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return hmac.compare_digest(encode_password(password), encoded)
|
return hmac.compare_digest(hash_password(password), hashed)
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ from app.lib.watchdogg import Watcher as WatchDog
|
|||||||
from app.periodic_scan import run_periodic_scans
|
from app.periodic_scan import run_periodic_scans
|
||||||
from app.plugins.register import register_plugins
|
from app.plugins.register import register_plugins
|
||||||
from app.settings import FLASKVARS, TCOLOR, Info
|
from app.settings import FLASKVARS, TCOLOR, Info
|
||||||
from app.setup import run_setup
|
from app.setup import load_into_mem, run_setup
|
||||||
from app.start_info_logger import log_startup_info
|
from app.start_info_logger import log_startup_info
|
||||||
from app.utils.filesystem import get_home_res_path
|
from app.utils.filesystem import get_home_res_path
|
||||||
from app.utils.paths import getClientFilesExtensions
|
from app.utils.paths import getClientFilesExtensions
|
||||||
@@ -47,10 +47,9 @@ mimetypes.add_type("application/manifest+json", ".webmanifest")
|
|||||||
werkzeug = logging.getLogger("werkzeug")
|
werkzeug = logging.getLogger("werkzeug")
|
||||||
werkzeug.setLevel(logging.ERROR)
|
werkzeug.setLevel(logging.ERROR)
|
||||||
|
|
||||||
|
|
||||||
# Background tasks
|
# Background tasks
|
||||||
@background
|
@background
|
||||||
def bg_run_setup() -> None:
|
def bg_run_setup():
|
||||||
run_periodic_scans()
|
run_periodic_scans()
|
||||||
|
|
||||||
|
|
||||||
@@ -71,9 +70,10 @@ def run_swingmusic():
|
|||||||
|
|
||||||
|
|
||||||
# Setup function calls
|
# Setup function calls
|
||||||
|
Info.load()
|
||||||
ProcessArgs()
|
ProcessArgs()
|
||||||
run_setup()
|
run_setup()
|
||||||
Info.load()
|
load_into_mem()
|
||||||
run_swingmusic()
|
run_swingmusic()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user