add utility to remove prod names from track titles

+ move code to handle args and print startup info to other files
+ update app version number
This commit is contained in:
geoffrey45 2023-02-17 18:25:32 +03:00
parent 29e766b60a
commit 509c22c736
8 changed files with 242 additions and 179 deletions

113
app/arg_handler.py Normal file
View File

@ -0,0 +1,113 @@
"""
Handles arguments passed to the program.
"""
import sys
from configparser import ConfigParser
import PyInstaller.__main__ as bundler
from app import settings
from app.print_help import HELP_MESSAGE
from app.utils import is_windows
config = ConfigParser()
config.read("pyinstaller.config.ini")
ALLARGS = settings.ALLARGS
ARGS = sys.argv[1:]
class HandleArgs:
def __init__(self) -> None:
self.handle_build()
self.handle_host()
self.handle_port()
self.handle_no_feat()
self.handle_remove_prod()
self.handle_help()
self.handle_version()
@staticmethod
def handle_build():
"""
Runs Pyinstaller.
"""
if ALLARGS.build in ARGS:
with open("pyinstaller.config.ini", "w", encoding="utf-8") as file:
config["DEFAULT"]["BUILD"] = "True"
config.write(file)
_s = ";" if is_windows() else ":"
bundler.run(
[
"manage.py",
"--onefile",
"--name",
"swingmusic",
"--clean",
f"--add-data=assets{_s}assets",
f"--add-data=client{_s}client",
f"--add-data=pyinstaller.config.ini{_s}.",
"-y",
]
)
with open("pyinstaller.config.ini", "w", encoding="utf-8") as file:
config["DEFAULT"]["BUILD"] = "False"
config.write(file)
sys.exit(0)
@staticmethod
def handle_port():
if ALLARGS.port in ARGS:
index = ARGS.index(ALLARGS.port)
try:
port = ARGS[index + 1]
except IndexError:
print("ERROR: Port not specified")
sys.exit(0)
try:
settings.FLASKVARS.FLASK_PORT = int(port) # type: ignore
except ValueError:
print("ERROR: Port should be a number")
sys.exit(0)
@staticmethod
def handle_host():
if ALLARGS.host in ARGS:
index = ARGS.index(ALLARGS.host)
try:
host = ARGS[index + 1]
except IndexError:
print("ERROR: Host not specified")
sys.exit(0)
settings.FLASKVARS.FLASK_HOST = host # type: ignore
@staticmethod
def handle_no_feat():
# if ArgsEnum.no_feat in ARGS:
if any((a in ARGS for a in ALLARGS.show_feat)):
settings.EXTRACT_FEAT = False
@staticmethod
def handle_remove_prod():
if any((a in ARGS for a in ALLARGS.show_prod)):
settings.REMOVE_PROD = False
@staticmethod
def handle_help():
if any((a in ARGS for a in ALLARGS.help)):
print(HELP_MESSAGE)
sys.exit(0)
@staticmethod
def handle_version():
if any((a in ARGS for a in ALLARGS.version)):
print(settings.APP_VERSION)
sys.exit(0)

View File

@ -61,16 +61,21 @@ class Track:
self.og_title = self.title
if self.artist is not None:
artists = utils.split_artists(self.artist)
new_title = self.title
if settings.EXTRACT_FEAT:
featured, new_title = utils.parse_feat_from_title(self.title)
original_lower = "-".join([a.lower() for a in artists])
artists.extend([a for a in featured if a.lower() not in original_lower])
self.title = new_title
if settings.REMOVE_PROD:
new_title = utils.remove_prod(new_title)
if self.og_title == self.album:
self.album = new_title
# if track is a single
if self.og_title == self.album:
self.album = new_title
self.title = new_title
self.artist_hashes = [utils.create_hash(a, decode=True) for a in artists]

18
app/print_help.py Normal file
View File

@ -0,0 +1,18 @@
from app.settings import ALLARGS
args = ALLARGS
HELP_MESSAGE = f"""
Usage: swingmusic [options]
Options:
{args.build}: Build the application (in development)
{args.host}: Set the host
{args.port}: Set the port
{', '.join(args.show_feat)}: Do not extract featured artists from the song title
{', '.join(args.show_prod)}: Do not hide producers in the song title
{', '.join(args.help)}: Show this help message
{', '.join(args.version)}: Show the app version
"""

View File

@ -28,7 +28,7 @@ def get_xdg_config_dir():
# ------- HELPER METHODS --------
APP_VERSION = "v.1.1.0.beta"
APP_VERSION = "v1.1.0"
# paths
XDG_CONFIG_DIR = get_xdg_config_dir()
@ -76,22 +76,34 @@ USER_DATA_DB_NAME = "userdata.db"
APP_DB_PATH = os.path.join(APP_DIR, APP_DB_NAME)
USERDATA_DB_PATH = os.path.join(APP_DIR, USER_DATA_DB_NAME)
HELP_MESSAGE = """
Usage: swingmusic [options]
Options:
--build: Build the application
--host: Set the host
--port: Set the port
--no-feat: Do not extract featured artists from the song title
--help, -h: Show this help message
--version, -v: Show the version
"""
class FLASKVARS:
FLASK_PORT = 1970
FLASK_HOST = "localhost"
class ALLARGS:
"""
Enumerates the possible app arguments.
"""
build = "--build"
port = "--port"
host = "--host"
show_feat = ["--show-feat", "-sf"]
show_prod = ["--show-prod", "-sp"]
help = ["--help", "-h"]
version = ["--version", "-v"]
EXTRACT_FEAT = True
"""
Whether to extract the featured artists from the song title.
Changed using the `--no-feat` flag
"""
REMOVE_PROD = True
"""
Whether to remove the producers from the song title.
"""

51
app/start_info_logger.py Normal file
View File

@ -0,0 +1,51 @@
import os
from app.utils import get_ip
from app.settings import TCOLOR, APP_VERSION, FLASKVARS, APP_DIR
from app import settings
def log_startup_info():
lines = "------------------------------"
# clears terminal 👇
os.system("cls" if os.name == "nt" else "echo -e \\\\033c")
print(lines)
print(f"{TCOLOR.HEADER}SwingMusic {APP_VERSION} {TCOLOR.ENDC}")
adresses = [FLASKVARS.FLASK_HOST]
if FLASKVARS.FLASK_HOST == "0.0.0.0":
adresses = ["localhost", get_ip()]
print("Started app on:")
for address in adresses:
# noinspection HttpUrlsUsage
print(
f"{TCOLOR.OKGREEN}http://{address}:{FLASKVARS.FLASK_PORT}{TCOLOR.ENDC}"
)
print(lines)
print("\n")
to_print = [
[
"Extract featured artists from titles",
settings.EXTRACT_FEAT
],
[
"Remove prod. from titles",
settings.REMOVE_PROD
]
]
for item in to_print:
print(
f"{item[0]}: {TCOLOR.FAIL}{item[1]}{TCOLOR.ENDC}"
)
print(
f"{TCOLOR.YELLOW}Data folder: {APP_DIR}{TCOLOR.ENDC}"
)
print("\n")

View File

@ -279,6 +279,7 @@ def parse_feat_from_title(title: str) -> tuple[list[str], str]:
artists = match.group(1)
artists = split_artists(artists, with_and=True)
print(artists)
# remove "feat" group from title
new_title = re.sub(regex, "", title, flags=re.IGNORECASE)
@ -334,10 +335,26 @@ def parse_title_from_filename(title: str):
return title
res = match.group(1)
# remove text in brackets starting with "official" case insensitive
# remove text in brackets starting with "official" case-insensitive
res = re.sub(r"\s*\([^)]*official[^)]*\)", "", res, flags=re.IGNORECASE)
return res.strip()
# for title in sample_titles:
# print(parse_artist_from_filename(title))
# print(parse_title_from_filename(title))
def remove_prod(title: str) -> str:
"""
Removes the producer string in a track title using regex.
"""
# check if title contain title, if not return it.
if not ("prod." in title.lower()):
return title
# check if title has brackets
if re.search(r'[()\[\]]', title):
regex = r'\s?(\(|\[)prod\..*?(\)|\])\s?'
else:
regex = r'\s?\bprod\.\s*\S+'
# remove the producer string
title = re.sub(regex, "", title, flags=re.IGNORECASE)
return title.strip()

165
manage.py
View File

@ -2,35 +2,22 @@
This file is used to run the application.
"""
import logging
import os
import sys
from configparser import ConfigParser
import PyInstaller.__main__ as bundler
from app import settings
from app.api import create_api
from app.arg_handler import HandleArgs
from app.functions import run_periodic_checks
from app.lib.watchdogg import Watcher as WatchDog
from app.settings import APP_VERSION, HELP_MESSAGE, TCOLOR
from app.settings import FLASKVARS
from app.setup import run_setup
from app.utils import background, get_home_res_path, get_ip, is_windows
from app.start_info_logger import log_startup_info
from app.utils import background, get_home_res_path
werkzeug = logging.getLogger("werkzeug")
werkzeug.setLevel(logging.ERROR)
class Variables:
FLASK_PORT = 1970
FLASK_HOST = "localhost"
app = create_api()
app.static_folder = get_home_res_path("client")
config = ConfigParser()
config.read("pyinstaller.config.ini")
@app.route("/<path:path>")
def serve_client_files(path):
@ -48,110 +35,6 @@ def serve_client():
return app.send_static_file("index.html")
ARGS = sys.argv[1:]
class ArgsEnum:
"""
Enumerates the possible file arguments.
"""
build = "--build"
port = "--port"
host = "--host"
no_feat = "--no-feat"
help = ["--help", "-h"]
version = ["--version", "-v"]
class HandleArgs:
def __init__(self) -> None:
self.handle_build()
self.handle_host()
self.handle_port()
self.handle_no_feat()
self.handle_help()
self.handle_version()
@staticmethod
def handle_build():
"""
Runs Pyinstaller.
"""
if ArgsEnum.build in ARGS:
with open("pyinstaller.config.ini", "w", encoding="utf-8") as file:
config["DEFAULT"]["BUILD"] = "True"
config.write(file)
_s = ";" if is_windows() else ":"
bundler.run(
[
"manage.py",
"--onefile",
"--name",
"swingmusic",
"--clean",
f"--add-data=assets{_s}assets",
f"--add-data=client{_s}client",
f"--add-data=pyinstaller.config.ini{_s}.",
"-y",
]
)
with open("pyinstaller.config.ini", "w", encoding="utf-8") as file:
config["DEFAULT"]["BUILD"] = "False"
config.write(file)
sys.exit(0)
@staticmethod
def handle_port():
if ArgsEnum.port in ARGS:
index = ARGS.index(ArgsEnum.port)
try:
port = ARGS[index + 1]
except IndexError:
print("ERROR: Port not specified")
sys.exit(0)
try:
Variables.FLASK_PORT = int(port) # type: ignore
except ValueError:
print("ERROR: Port should be a number")
sys.exit(0)
@staticmethod
def handle_host():
if ArgsEnum.host in ARGS:
index = ARGS.index(ArgsEnum.host)
try:
host = ARGS[index + 1]
except IndexError:
print("ERROR: Host not specified")
sys.exit(0)
Variables.FLASK_HOST = host # type: ignore
@staticmethod
def handle_no_feat():
if ArgsEnum.no_feat in ARGS:
settings.EXTRACT_FEAT = False
@staticmethod
def handle_help():
if any((a in ARGS for a in ArgsEnum.help)):
print(HELP_MESSAGE)
sys.exit(0)
@staticmethod
def handle_version():
if any((a in ARGS for a in ArgsEnum.version)):
print(APP_VERSION)
sys.exit(0)
@background
def run_bg_checks() -> None:
run_setup()
@ -163,41 +46,6 @@ def start_watchdog():
WatchDog().run()
def log_startup_info():
lines = "------------------------------"
# clears terminal 👇
os.system("cls" if os.name == "nt" else "echo -e \\\\033c")
print(lines)
print(f"{TCOLOR.HEADER}SwingMusic {APP_VERSION} {TCOLOR.ENDC}")
adresses = [Variables.FLASK_HOST]
if Variables.FLASK_HOST == "0.0.0.0":
adresses = ["localhost", get_ip()]
print("Started app on:")
for address in adresses:
# noinspection HttpUrlsUsage
print(
f"{TCOLOR.OKGREEN}http://{address}:{Variables.FLASK_PORT}{TCOLOR.ENDC}"
)
print(lines)
print("\n")
if not settings.EXTRACT_FEAT:
print(
f"{TCOLOR.OKBLUE}Extracting featured artists from track titles: {TCOLOR.FAIL}DISABLED!{TCOLOR.ENDC}"
)
print(
f"{TCOLOR.OKBLUE}App data folder: {settings.APP_DIR}{TCOLOR.OKGREEN}{TCOLOR.ENDC}"
)
print("\n")
if __name__ == "__main__":
HandleArgs()
log_startup_info()
@ -207,10 +55,9 @@ if __name__ == "__main__":
app.run(
debug=False,
threaded=True,
host=Variables.FLASK_HOST,
port=Variables.FLASK_PORT,
host=FLASKVARS.FLASK_HOST,
port=FLASKVARS.FLASK_PORT,
use_reloader=False,
)
# TODO: Find a way to verify the host string
# TODO: Organize code in this file: move args to new file, etc.

View File

@ -24,7 +24,7 @@ def test_extract_featured_artists_from_title():
]
for title, expected in zip(test_titles, results):
assert parse_feat_from_title(title) == expected
assert parse_feat_from_title(title)[0] == expected
# === HYPOTHESIS GHOSTWRITER TESTS ===