mirror of
https://github.com/tcsenpai/swingmusic.git
synced 2025-06-06 03:05:35 +00:00
redesign progressbars
+ hide some progressbars + rewrite telemetry into a class + remove obsolete start info logs + update contributing.md to include contributing.md + send posthog event in a bg thread + related side effects
This commit is contained in:
parent
54714a224b
commit
4f757e989f
4
.github/contributing.md
vendored
4
.github/contributing.md
vendored
@ -39,7 +39,9 @@ cd swingmusic
|
||||
poetry install
|
||||
```
|
||||
|
||||
Run the server. You can use a different port if you have another Swing Music instance running on the default port `1970`.
|
||||
You need a LastFM API key which you can get on the [API accounts page](https://www.last.fm/api/accounts). Then set it as an environment variable under the name: `LASTFM_API_KEY`.
|
||||
|
||||
Finally, run the server. You can use a different port if you have another Swing Music instance running on port `1970`.
|
||||
|
||||
```sh
|
||||
poetry run python manage.py --port 1980
|
||||
|
@ -15,17 +15,23 @@ from app.serializers.track import serialize_tracks
|
||||
from app.store.albums import AlbumStore
|
||||
from app.store.artists import ArtistStore
|
||||
from app.store.tracks import TrackStore
|
||||
from app import telemetry
|
||||
from app.telemetry import Telemetry
|
||||
from app.utils.threading import background
|
||||
|
||||
api = Blueprint("artist", __name__, url_prefix="/")
|
||||
|
||||
|
||||
@background
|
||||
def send_event():
|
||||
Telemetry.send_artist_visited()
|
||||
|
||||
|
||||
@api.route("/artist/<artisthash>", methods=["GET"])
|
||||
def get_artist(artisthash: str):
|
||||
"""
|
||||
Get artist data.
|
||||
"""
|
||||
telemetry.send_artist_visited()
|
||||
send_event()
|
||||
limit = request.args.get("limit")
|
||||
|
||||
if limit is None:
|
||||
|
@ -34,6 +34,9 @@ class HandleArgs:
|
||||
Runs Pyinstaller.
|
||||
"""
|
||||
|
||||
if ALLARGS.build not in ARGS:
|
||||
return
|
||||
|
||||
if settings.IS_BUILD:
|
||||
print("Catch me if you can! 😆💬")
|
||||
sys.exit(0)
|
||||
@ -49,7 +52,6 @@ class HandleArgs:
|
||||
log.error("ERROR: POSTHOG_API_KEY not set in environment")
|
||||
sys.exit(0)
|
||||
|
||||
if ALLARGS.build in ARGS:
|
||||
try:
|
||||
with open("./app/configs.py", "w", encoding="utf-8") as file:
|
||||
# copy the api keys to the config file
|
||||
|
@ -28,8 +28,6 @@ class SettingsSQLMethods:
|
||||
if settings is None:
|
||||
return []
|
||||
|
||||
# print
|
||||
|
||||
# omit id, root_dirs, and exclude_dirs
|
||||
return settings[3:]
|
||||
|
||||
|
@ -8,12 +8,12 @@ import requests
|
||||
from PIL import Image, UnidentifiedImageError
|
||||
from requests.exceptions import ConnectionError as RequestConnectionError
|
||||
from requests.exceptions import ReadTimeout
|
||||
from tqdm import tqdm
|
||||
|
||||
from app import settings
|
||||
from app.models import Album, Artist, Track
|
||||
from app.store import artists as artist_store
|
||||
from app.utils.hashing import create_hash
|
||||
from app.utils.progressbar import tqdm
|
||||
|
||||
|
||||
CHECK_ARTIST_IMAGES_KEY = ""
|
||||
|
@ -6,7 +6,6 @@ import json
|
||||
from pathlib import Path
|
||||
|
||||
import colorgram
|
||||
from tqdm import tqdm
|
||||
|
||||
from app import settings
|
||||
from app.db.sqlite.albumcolors import SQLiteAlbumMethods as aldb
|
||||
@ -17,6 +16,7 @@ from app.store.artists import ArtistStore
|
||||
from app.store.albums import AlbumStore
|
||||
from app.logger import log
|
||||
from app.lib.errors import PopulateCancelledError
|
||||
from app.utils.progressbar import tqdm
|
||||
|
||||
PROCESS_ALBUM_COLORS_KEY = ""
|
||||
PROCESS_ARTIST_COLORS_KEY = ""
|
||||
|
@ -5,7 +5,6 @@ from typing import Generator
|
||||
|
||||
from requests import ConnectionError as RequestConnectionError
|
||||
from requests import ReadTimeout
|
||||
from tqdm import tqdm
|
||||
|
||||
from app import settings
|
||||
from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb
|
||||
@ -28,6 +27,7 @@ from app.store.artists import ArtistStore
|
||||
from app.store.tracks import TrackStore
|
||||
from app.utils.filesystem import run_fast_scandir
|
||||
from app.utils.network import has_connection
|
||||
from app.utils.progressbar import tqdm
|
||||
|
||||
get_all_tracks = SQLiteTrackMethods.get_all_tracks
|
||||
insert_many_tracks = SQLiteTrackMethods.insert_many_tracks
|
||||
|
@ -3,11 +3,10 @@ This library contains all the functions related to tracks.
|
||||
"""
|
||||
import os
|
||||
|
||||
from tqdm import tqdm
|
||||
|
||||
from app.db.sqlite.tracks import SQLiteTrackMethods as tdb
|
||||
from app.store.tracks import TrackStore
|
||||
|
||||
from app.utils.progressbar import tqdm
|
||||
|
||||
def validate_tracks() -> None:
|
||||
"""
|
||||
|
@ -2,6 +2,7 @@
|
||||
Logger module
|
||||
"""
|
||||
|
||||
from app.settings import IS_BUILD
|
||||
import logging
|
||||
|
||||
|
||||
|
@ -104,7 +104,7 @@ class Album:
|
||||
"""
|
||||
keywords = ["motion picture", "soundtrack"]
|
||||
for keyword in keywords:
|
||||
if keyword in self.title.lower():
|
||||
if keyword in self.og_title.lower():
|
||||
return True
|
||||
|
||||
return False
|
||||
@ -145,7 +145,7 @@ class Album:
|
||||
"""
|
||||
keywords = ["live from", "live at", "live in", "live on", "mtv unplugged"]
|
||||
for keyword in keywords:
|
||||
if keyword in self.title.lower():
|
||||
if keyword in self.og_title.lower():
|
||||
return True
|
||||
|
||||
return False
|
||||
@ -165,7 +165,7 @@ class Album:
|
||||
show_albums_as_singles = get_flag(SessionVarKeys.SHOW_ALBUMS_AS_SINGLES)
|
||||
|
||||
for keyword in keywords:
|
||||
if keyword in self.title.lower():
|
||||
if keyword in self.og_title.lower():
|
||||
self.is_single = True
|
||||
return
|
||||
|
||||
|
@ -13,7 +13,7 @@ help_args_list = [
|
||||
[
|
||||
"--scan-interval",
|
||||
"-psi",
|
||||
"Set the periodic scan interval in seconds. Default is 600 seconds (10 minutes)",
|
||||
"Set the scan interval in seconds. Default 600s (10 minutes)",
|
||||
],
|
||||
[
|
||||
"--build",
|
||||
@ -26,9 +26,7 @@ HELP_MESSAGE = f"""
|
||||
Swing Music is a beautiful, self-hosted music player for your
|
||||
local audio files. Like a cooler Spotify ... but bring your own music.
|
||||
|
||||
Usage: swingmusic [options]
|
||||
Usage: swingmusic [options] [args]
|
||||
|
||||
{tabulate(help_args_list, headers=["Option", "Short", "Description"], tablefmt="markdown", maxcolwidths=[None, None, 44])}
|
||||
{tabulate(help_args_list, headers=["Option", "Short", "Description"], tablefmt="simple_grid", maxcolwidths=[None, None, 40])}
|
||||
"""
|
||||
|
||||
"80s, 90s, the noughties and today"
|
||||
|
@ -6,7 +6,6 @@ import sys
|
||||
from typing import Any
|
||||
|
||||
from app import configs
|
||||
from app.logger import log
|
||||
|
||||
join = os.path.join
|
||||
|
||||
@ -241,14 +240,10 @@ class Keys:
|
||||
cls.LASTFM_API = configs.LASTFM_API_KEY
|
||||
cls.POSTHOG_API_KEY = configs.POSTHOG_API_KEY
|
||||
|
||||
cls.verify_exists()
|
||||
cls.verify_keys()
|
||||
|
||||
@classmethod
|
||||
def verify_exists(cls):
|
||||
def verify_keys(cls):
|
||||
if not cls.LASTFM_API:
|
||||
log.error("ERROR: LASTFM_API_KEY not set in environment")
|
||||
sys.exit(0)
|
||||
|
||||
if not cls.POSTHOG_API_KEY:
|
||||
log.error("ERROR: POSTHOG_API_KEY not set in environment")
|
||||
print("ERROR: LASTFM_API_KEY not set in environment")
|
||||
sys.exit(0)
|
||||
|
@ -1,7 +1,6 @@
|
||||
import os
|
||||
|
||||
from app.settings import (FLASKVARS, TCOLOR, Paths, Release, SessionVarKeys,
|
||||
get_flag)
|
||||
from app.settings import FLASKVARS, TCOLOR, Paths, Release
|
||||
from app.utils.network import get_ip
|
||||
|
||||
|
||||
@ -25,27 +24,8 @@ def log_startup_info():
|
||||
f"➤ {TCOLOR.OKGREEN}http://{address}:{FLASKVARS.get_flask_port()}{TCOLOR.ENDC}"
|
||||
)
|
||||
|
||||
print(lines)
|
||||
print("\n")
|
||||
print(lines+"\n")
|
||||
|
||||
to_print = [
|
||||
[
|
||||
"Extract featured artists from titles",
|
||||
get_flag(SessionVarKeys.EXTRACT_FEAT)
|
||||
],
|
||||
[
|
||||
"Remove prod. from titles",
|
||||
get_flag(SessionVarKeys.REMOVE_PROD)
|
||||
]
|
||||
]
|
||||
|
||||
for item in to_print:
|
||||
print(
|
||||
f"{item[0]}: {TCOLOR.FAIL}{item[1]}{TCOLOR.ENDC}"
|
||||
)
|
||||
|
||||
print(
|
||||
f"{TCOLOR.YELLOW}Data folder: {Paths.get_app_dir()}{TCOLOR.ENDC}"
|
||||
)
|
||||
print(f"{TCOLOR.YELLOW}Data folder: {Paths.get_app_dir()}{TCOLOR.ENDC}")
|
||||
|
||||
print("\n")
|
||||
|
@ -1,13 +1,13 @@
|
||||
import json
|
||||
import random
|
||||
|
||||
from tqdm import tqdm
|
||||
|
||||
from app.db.sqlite.albumcolors import SQLiteAlbumMethods as aldb
|
||||
from app.models import Album, Track
|
||||
|
||||
from ..utils.hashing import create_hash
|
||||
from .tracks import TrackStore
|
||||
from app.utils.progressbar import tqdm
|
||||
|
||||
ALBUM_LOAD_KEY = ""
|
||||
|
||||
@ -49,7 +49,7 @@ class AlbumStore:
|
||||
|
||||
db_albums: list[tuple] = aldb.get_all_albums()
|
||||
|
||||
for album in tqdm(db_albums, desc="Mapping album colors"):
|
||||
for album in db_albums:
|
||||
albumhash = album[1]
|
||||
colors = json.loads(album[2])
|
||||
|
||||
|
@ -1,11 +1,10 @@
|
||||
import json
|
||||
|
||||
from tqdm import tqdm
|
||||
|
||||
from app.db.sqlite.artistcolors import SQLiteArtistMethods as ardb
|
||||
from app.lib.artistlib import get_all_artists
|
||||
from app.models import Artist
|
||||
from app.utils.bisection import UseBisection
|
||||
from app.utils.progressbar import tqdm
|
||||
|
||||
from .albums import AlbumStore
|
||||
from .tracks import TrackStore
|
||||
@ -26,9 +25,7 @@ class ArtistStore:
|
||||
|
||||
cls.artists = get_all_artists(TrackStore.tracks, AlbumStore.albums)
|
||||
|
||||
# db_artists: list[tuple] = list(ardb.get_all_artists())
|
||||
|
||||
for artist in tqdm(ardb.get_all_artists(), desc="Loading artists"):
|
||||
for artist in ardb.get_all_artists():
|
||||
if instance_key != ARTIST_LOAD_KEY:
|
||||
return
|
||||
|
||||
|
@ -1,10 +1,11 @@
|
||||
from tqdm import tqdm
|
||||
# from tqdm import tqdm
|
||||
|
||||
from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb
|
||||
from app.db.sqlite.tracks import SQLiteTrackMethods as tdb
|
||||
from app.models import Track
|
||||
from app.utils.bisection import UseBisection
|
||||
from app.utils.remove_duplicates import remove_duplicates
|
||||
from app.utils.progressbar import tqdm
|
||||
|
||||
TRACKS_LOAD_KEY = ""
|
||||
|
||||
@ -25,6 +26,7 @@ class TrackStore:
|
||||
fav_hashes = favdb.get_fav_tracks()
|
||||
fav_hashes = " ".join([t[1] for t in fav_hashes])
|
||||
|
||||
print("\n") # adds space between progress bars and startup info
|
||||
for track in tqdm(cls.tracks, desc="Loading tracks"):
|
||||
if instance_key != TRACKS_LOAD_KEY:
|
||||
return
|
||||
|
@ -2,55 +2,69 @@ import sys
|
||||
import uuid as UUID
|
||||
|
||||
from posthog import Posthog
|
||||
from app.settings import Paths, Keys
|
||||
|
||||
from app.logger import log
|
||||
from app.settings import Keys, Paths, Release
|
||||
from app.utils.hashing import create_hash
|
||||
from app.utils.network import has_connection
|
||||
from app.logger import log
|
||||
|
||||
|
||||
USER_ID = ""
|
||||
class Telemetry:
|
||||
"""
|
||||
Handles sending telemetry data to posthog.
|
||||
"""
|
||||
|
||||
user_id = ""
|
||||
off = False
|
||||
|
||||
@classmethod
|
||||
def init(cls) -> None:
|
||||
try:
|
||||
posthog = Posthog(
|
||||
cls.posthog = Posthog(
|
||||
project_api_key=Keys.POSTHOG_API_KEY,
|
||||
host="https://app.posthog.com",
|
||||
disable_geoip=False,
|
||||
timeout=30,
|
||||
)
|
||||
|
||||
cls.create_userid()
|
||||
except AssertionError:
|
||||
log.error("ERROR: POSTHOG_API_KEY not set in environment")
|
||||
sys.exit(0)
|
||||
cls.disable_telemetry()
|
||||
|
||||
|
||||
def create_userid():
|
||||
@classmethod
|
||||
def create_userid(cls):
|
||||
"""
|
||||
Creates a unique user id for the user and saves it to a file.
|
||||
"""
|
||||
uuid_path = Paths.get_app_dir() + "/userid.txt"
|
||||
global USER_ID
|
||||
|
||||
try:
|
||||
with open(uuid_path, "r") as f:
|
||||
USER_ID = f.read().strip()
|
||||
cls.user_id = f.read().strip()
|
||||
except FileNotFoundError:
|
||||
uuid = str(UUID.uuid4())
|
||||
USER_ID = "user_" + create_hash(uuid, limit=15)
|
||||
cls.user_id = "user_" + create_hash(uuid, limit=15)
|
||||
|
||||
with open(uuid_path, "w") as f:
|
||||
f.write(USER_ID)
|
||||
f.write(cls.user_id)
|
||||
|
||||
@classmethod
|
||||
def disable_telemetry(cls):
|
||||
cls.off = True
|
||||
|
||||
def send_event(event: str):
|
||||
@classmethod
|
||||
def send_event(cls, event: str):
|
||||
"""
|
||||
Sends an event to posthog.
|
||||
"""
|
||||
global USER_ID
|
||||
if cls.off:
|
||||
return
|
||||
|
||||
if has_connection():
|
||||
posthog.capture(USER_ID, event=f"v1.3.0-{event}")
|
||||
cls.posthog.capture(cls.user_id, event=f"v{Release.APP_VERSION}-{event}")
|
||||
|
||||
|
||||
def send_artist_visited():
|
||||
@classmethod
|
||||
def send_artist_visited(cls):
|
||||
"""
|
||||
Sends an event to posthog when an artist page is visited.
|
||||
"""
|
||||
send_event("artist-page-visited")
|
||||
cls.send_event("artist-page-visited")
|
||||
|
16
app/utils/progressbar.py
Normal file
16
app/utils/progressbar.py
Normal file
@ -0,0 +1,16 @@
|
||||
from tqdm import tqdm as _tqdm
|
||||
|
||||
|
||||
def tqdm(*args, **kwargs):
|
||||
"""
|
||||
Wrapper for tqdm that sets globals.
|
||||
"""
|
||||
bar_format = "{percentage:3.0f}%|{bar:45}|{n_fmt}/{total_fmt}{desc}"
|
||||
kwargs["bar_format"] = bar_format
|
||||
|
||||
if "desc" in kwargs:
|
||||
print(f'INFO|{kwargs["desc"].capitalize()} ...')
|
||||
kwargs["desc"] = ""
|
||||
|
||||
|
||||
return _tqdm(*args, **kwargs)
|
@ -3,8 +3,7 @@ import threading
|
||||
|
||||
def background(func):
|
||||
"""
|
||||
a threading decorator
|
||||
use @background above the function you want to run in the background
|
||||
Runs the decorated function in a background thread.
|
||||
"""
|
||||
|
||||
def background_func(*a, **kw):
|
||||
|
@ -8,7 +8,7 @@ import os
|
||||
import setproctitle
|
||||
from flask import request
|
||||
|
||||
from app import telemetry
|
||||
from app.telemetry import Telemetry
|
||||
from app.api import create_api
|
||||
from app.arg_handler import HandleArgs
|
||||
from app.lib.watchdogg import Watcher as WatchDog
|
||||
@ -79,13 +79,18 @@ def start_watchdog():
|
||||
WatchDog().run()
|
||||
|
||||
|
||||
@background
|
||||
def init_telemetry():
|
||||
Telemetry.init()
|
||||
|
||||
|
||||
def run_swingmusic():
|
||||
Keys.load()
|
||||
HandleArgs()
|
||||
log_startup_info()
|
||||
bg_run_setup()
|
||||
start_watchdog()
|
||||
telemetry.create_userid()
|
||||
init_telemetry()
|
||||
|
||||
setproctitle.setproctitle(
|
||||
f"swingmusic - {FLASKVARS.FLASK_HOST}:{FLASKVARS.FLASK_PORT}"
|
||||
|
Loading…
x
Reference in New Issue
Block a user