mirror of
https://github.com/Dvorinka/swingmusic-extended.git
synced 2026-06-03 20:13:02 +00:00
fix: new user recently played data not being shown in homepage
+ fix: weird role labels on new users + remove system status tray + fix: tinytag removing b prefix on tags
This commit is contained in:
+1
-1
@@ -12,7 +12,7 @@ dependencies = [
|
|||||||
"requests>=2.27.1",
|
"requests>=2.27.1",
|
||||||
"colorgram.py>=1.2.0",
|
"colorgram.py>=1.2.0",
|
||||||
"tqdm>=4.65.0",
|
"tqdm>=4.65.0",
|
||||||
"tinytag>=2.0.0",
|
"tinytag>=2.1.1",
|
||||||
"Unidecode>=1.3.6",
|
"Unidecode>=1.3.6",
|
||||||
"psutil>=5.9.4",
|
"psutil>=5.9.4",
|
||||||
"show-in-file-manager>=1.1.4",
|
"show-in-file-manager>=1.1.4",
|
||||||
|
|||||||
+1
-37
@@ -2,11 +2,8 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import click
|
import click
|
||||||
import pathlib
|
import pathlib
|
||||||
import pystray
|
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
from typing import Callable
|
|
||||||
from pystray._base import Icon as PystrayIcon
|
|
||||||
|
|
||||||
from swingmusic.start_swingmusic import start_swingmusic
|
from swingmusic.start_swingmusic import start_swingmusic
|
||||||
from swingmusic.utils.xdg_utils import get_xdg_config_dir
|
from swingmusic.utils.xdg_utils import get_xdg_config_dir
|
||||||
@@ -14,30 +11,6 @@ from swingmusic.utils.filesystem import get_home_res_path
|
|||||||
from swingmusic.arg_handler import handle_build, handle_password_reset
|
from swingmusic.arg_handler import handle_build, handle_password_reset
|
||||||
|
|
||||||
|
|
||||||
class App:
|
|
||||||
def __init__(self, host: str, port: int, setup: Callable[[], None]):
|
|
||||||
self.host: str = host
|
|
||||||
self.port: int = port
|
|
||||||
self.icon: PystrayIcon = None
|
|
||||||
self.setup = setup
|
|
||||||
self.process = multiprocessing.Process(
|
|
||||||
target=self.setup, args=(self.host, self.port)
|
|
||||||
)
|
|
||||||
|
|
||||||
def start(self, icon: PystrayIcon):
|
|
||||||
self.icon = icon
|
|
||||||
self.icon.visible = True
|
|
||||||
self.process.start()
|
|
||||||
self.icon.run()
|
|
||||||
|
|
||||||
def stop(self):
|
|
||||||
print("\nShutting down ...", end=" ")
|
|
||||||
self.process.terminate()
|
|
||||||
self.process.join(timeout=1)
|
|
||||||
self.icon.stop()
|
|
||||||
print("bye! 👋")
|
|
||||||
|
|
||||||
|
|
||||||
def create_image(width, height, color1, color2):
|
def create_image(width, height, color1, color2):
|
||||||
# Generate an image and draw a pattern
|
# Generate an image and draw a pattern
|
||||||
padding = 7
|
padding = 7
|
||||||
@@ -132,16 +105,7 @@ def run(*args, **kwargs):
|
|||||||
os.environ["SWINGMUSIC_XDG_CONFIG_DIR"] = str(
|
os.environ["SWINGMUSIC_XDG_CONFIG_DIR"] = str(
|
||||||
pathlib.Path(kwargs["config"]).resolve()
|
pathlib.Path(kwargs["config"]).resolve()
|
||||||
)
|
)
|
||||||
|
start_swingmusic(kwargs["host"], kwargs["port"])
|
||||||
app = App(kwargs["host"], kwargs["port"], start_swingmusic)
|
|
||||||
icon = pystray.Icon(
|
|
||||||
"Swing Music",
|
|
||||||
icon=create_image(64, 64, "black", "white"),
|
|
||||||
menu=pystray.Menu(
|
|
||||||
pystray.MenuItem("Quit Swing Music", app.stop),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
app.start(icon)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ from flask_openapi3 import Tag
|
|||||||
from flask_openapi3 import APIBlueprint
|
from flask_openapi3 import APIBlueprint
|
||||||
|
|
||||||
from swingmusic.db.userdata import UserTable
|
from swingmusic.db.userdata import UserTable
|
||||||
|
from swingmusic.store.homepage import HomepageStore
|
||||||
from swingmusic.utils.auth import check_password, hash_password
|
from swingmusic.utils.auth import check_password, hash_password
|
||||||
from swingmusic.config import UserConfig
|
from swingmusic.config import UserConfig
|
||||||
|
|
||||||
@@ -172,7 +173,6 @@ def update_profile(body: UpdateProfileBody):
|
|||||||
if "admin" not in current_user["roles"]:
|
if "admin" not in current_user["roles"]:
|
||||||
return {"msg": "Only admins can update roles"}, 403
|
return {"msg": "Only admins can update roles"}, 403
|
||||||
|
|
||||||
# all_users = authdb.get_all_users()
|
|
||||||
all_users = UserTable.get_all()
|
all_users = UserTable.get_all()
|
||||||
if "admin" not in body.roles:
|
if "admin" not in body.roles:
|
||||||
# check if we're removing the last admin
|
# check if we're removing the last admin
|
||||||
@@ -187,7 +187,7 @@ def update_profile(body: UpdateProfileBody):
|
|||||||
return {"msg": "Cannot update guest user"}, 400
|
return {"msg": "Cannot update guest user"}, 400
|
||||||
|
|
||||||
# finally, convert roles to json string
|
# finally, convert roles to json string
|
||||||
user["roles"] = json.dumps(body.roles)
|
user["roles"] = body.roles
|
||||||
|
|
||||||
if user["password"]:
|
if user["password"]:
|
||||||
user["password"] = hash_password(user["password"])
|
user["password"] = hash_password(user["password"])
|
||||||
@@ -215,7 +215,7 @@ def create_user(body: UpdateProfileBody):
|
|||||||
user = {
|
user = {
|
||||||
"username": body.username,
|
"username": body.username,
|
||||||
"password": hash_password(body.password),
|
"password": hash_password(body.password),
|
||||||
"roles": json.dumps([]),
|
"roles": [],
|
||||||
}
|
}
|
||||||
|
|
||||||
# check if user already exists
|
# check if user already exists
|
||||||
@@ -226,6 +226,7 @@ def create_user(body: UpdateProfileBody):
|
|||||||
user = UserTable.get_by_username(user["username"])
|
user = UserTable.get_by_username(user["username"])
|
||||||
|
|
||||||
if user:
|
if user:
|
||||||
|
HomepageStore.entries["recently_played"].add_new_user(user.id)
|
||||||
return user.todict()
|
return user.todict()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -247,9 +248,12 @@ def create_guest_user():
|
|||||||
"msg": "Guest user already exists",
|
"msg": "Guest user already exists",
|
||||||
}, 400
|
}, 400
|
||||||
|
|
||||||
userid = UserTable.insert_guest_user()
|
UserTable.insert_guest_user()
|
||||||
|
user = UserTable.get_by_username("guest")
|
||||||
|
|
||||||
|
if user:
|
||||||
|
HomepageStore.entries["recently_played"].add_new_user(user.id)
|
||||||
|
|
||||||
if userid:
|
|
||||||
return {
|
return {
|
||||||
"msg": "Guest user created",
|
"msg": "Guest user created",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
from dataclasses import asdict
|
from dataclasses import asdict
|
||||||
import datetime
|
import datetime
|
||||||
|
import json
|
||||||
from typing import Any, Iterable, Literal
|
from typing import Any, Iterable, Literal
|
||||||
from sqlalchemy import (
|
from sqlalchemy import (
|
||||||
JSON,
|
JSON,
|
||||||
@@ -15,7 +16,7 @@ from sqlalchemy import (
|
|||||||
update,
|
update,
|
||||||
)
|
)
|
||||||
|
|
||||||
from sqlalchemy.orm import Mapped, mapped_column, sessionmaker
|
from sqlalchemy.orm import Mapped, mapped_column
|
||||||
|
|
||||||
from swingmusic.db.engine import DbEngine
|
from swingmusic.db.engine import DbEngine
|
||||||
from swingmusic.db.utils import (
|
from swingmusic.db.utils import (
|
||||||
@@ -40,7 +41,7 @@ class UserTable(Base):
|
|||||||
image: Mapped[str] = mapped_column(String(), nullable=True)
|
image: Mapped[str] = mapped_column(String(), nullable=True)
|
||||||
password: Mapped[str] = mapped_column(String())
|
password: Mapped[str] = mapped_column(String())
|
||||||
username: Mapped[str] = mapped_column(String(), index=True)
|
username: Mapped[str] = mapped_column(String(), index=True)
|
||||||
roles: Mapped[list[str]] = mapped_column(JSON(), default_factory=lambda: ["user"])
|
roles: Mapped[list[str]] = mapped_column(JSON(), default_factory=lambda: [])
|
||||||
extra: Mapped[dict[str, Any]] = mapped_column(
|
extra: Mapped[dict[str, Any]] = mapped_column(
|
||||||
JSON(), nullable=True, default_factory=dict
|
JSON(), nullable=True, default_factory=dict
|
||||||
)
|
)
|
||||||
@@ -82,13 +83,6 @@ class UserTable(Base):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_by_username(cls, username: str):
|
def get_by_username(cls, username: str):
|
||||||
# with DbEngine.manager() as conn:
|
|
||||||
# result = conn.execute(select(cls).where(cls.username == username))
|
|
||||||
# res = result.fetchone()
|
|
||||||
|
|
||||||
# if res:
|
|
||||||
# return user_to_dataclass(res)
|
|
||||||
|
|
||||||
res = cls.execute(select(cls).where(cls.username == username))
|
res = cls.execute(select(cls).where(cls.username == username))
|
||||||
res = next(res).scalar()
|
res = next(res).scalar()
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
|
from swingmusic.db.userdata import ScrobbleTable
|
||||||
from swingmusic.models.playlist import Playlist
|
from swingmusic.models.playlist import Playlist
|
||||||
from swingmusic.lib.playlistlib import get_first_4_images
|
from swingmusic.lib.playlistlib import get_first_4_images
|
||||||
from swingmusic.utils.dates import (
|
from swingmusic.utils.dates import (
|
||||||
@@ -20,7 +21,11 @@ def get_recently_played_playlist(limit: int = 100):
|
|||||||
trackhashes=[],
|
trackhashes=[],
|
||||||
)
|
)
|
||||||
|
|
||||||
tracks = TrackStore.get_recently_played(limit)
|
scrobbles = ScrobbleTable.get_all(None, 100)
|
||||||
|
tracks = TrackStore.get_tracks_by_trackhashes(
|
||||||
|
[scrobble.trackhash for scrobble in scrobbles]
|
||||||
|
)
|
||||||
|
|
||||||
date = datetime.fromtimestamp(tracks[0].lastplayed)
|
date = datetime.fromtimestamp(tracks[0].lastplayed)
|
||||||
playlist._last_updated = date_string_to_time_passed(create_new_date(date))
|
playlist._last_updated = date_string_to_time_passed(create_new_date(date))
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from swingmusic.db.userdata import FavoritesTable, MixTable, PlaylistTable
|
from swingmusic.db.userdata import FavoritesTable, PlaylistTable
|
||||||
from swingmusic.lib.home import find_mix
|
from swingmusic.lib.home import find_mix
|
||||||
from swingmusic.lib.home.recentlyadded import get_recently_added_playlist
|
from swingmusic.lib.home.recentlyadded import get_recently_added_playlist
|
||||||
from swingmusic.lib.home.recentlyplayed import get_recently_played_playlist
|
from swingmusic.lib.home.recentlyplayed import get_recently_played_playlist
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import pprint
|
|
||||||
from swingmusic.db.userdata import ScrobbleTable, UserTable
|
from swingmusic.db.userdata import ScrobbleTable, UserTable
|
||||||
from swingmusic.lib.home.recentlyadded import get_recently_added_items
|
from swingmusic.lib.home.recentlyadded import get_recently_added_items
|
||||||
from swingmusic.lib.home.get_recently_played import get_recently_played
|
from swingmusic.lib.home.get_recently_played import get_recently_played
|
||||||
|
|||||||
@@ -18,6 +18,13 @@ class User:
|
|||||||
this_dict = asdict(self)
|
this_dict = asdict(self)
|
||||||
del this_dict["password"]
|
del this_dict["password"]
|
||||||
|
|
||||||
|
if type(this_dict["roles"]) is str:
|
||||||
|
# INFO: this is an attempt to fix string roles!
|
||||||
|
try:
|
||||||
|
this_dict["roles"] = json.loads(this_dict["roles"])
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
this_dict["roles"] = []
|
||||||
|
|
||||||
return this_dict
|
return this_dict
|
||||||
|
|
||||||
def todict_simplified(self):
|
def todict_simplified(self):
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ class HomepageStore:
|
|||||||
Stores the homepage items.
|
Stores the homepage items.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# INFO: map of entry names to entry objects
|
||||||
entries: dict[str, HomepageEntry] = {
|
entries: dict[str, HomepageEntry] = {
|
||||||
"recently_played": RecentlyPlayedHomepageEntry(
|
"recently_played": RecentlyPlayedHomepageEntry(
|
||||||
title="Recently played",
|
title="Recently played",
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ from typing import Any
|
|||||||
from swingmusic.lib.home.recover_items import recover_items
|
from swingmusic.lib.home.recover_items import recover_items
|
||||||
from swingmusic.models.mix import Mix
|
from swingmusic.models.mix import Mix
|
||||||
|
|
||||||
|
|
||||||
class HomepageEntry(ABC):
|
class HomepageEntry(ABC):
|
||||||
"""
|
"""
|
||||||
Base class for all homepage entries.
|
Base class for all homepage entries.
|
||||||
@@ -70,6 +71,12 @@ class RecentlyPlayedHomepageEntry(HomepageEntry):
|
|||||||
super().__init__(title, description)
|
super().__init__(title, description)
|
||||||
self.items = {}
|
self.items = {}
|
||||||
|
|
||||||
|
def add_new_user(self, userid: int):
|
||||||
|
"""
|
||||||
|
Add a new user to the homepage entry.
|
||||||
|
"""
|
||||||
|
self.items[userid] = []
|
||||||
|
|
||||||
def get_items(self, userid: int, limit: int | None = None):
|
def get_items(self, userid: int, limit: int | None = None):
|
||||||
items = self.items.get(userid, [])[:limit]
|
items = self.items.get(userid, [])[:limit]
|
||||||
|
|
||||||
@@ -115,4 +122,3 @@ class BecauseYouListenedToArtistHomepageEntry(RecentlyPlayedHomepageEntry):
|
|||||||
"title": title,
|
"title": title,
|
||||||
"items": recover_items(items),
|
"items": recover_items(items),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -198,7 +198,6 @@ class TrackStore:
|
|||||||
Returns a list of tracks by their hashes.
|
Returns a list of tracks by their hashes.
|
||||||
"""
|
"""
|
||||||
hash_set = set(trackhashes)
|
hash_set = set(trackhashes)
|
||||||
|
|
||||||
tracks: list[Track] = []
|
tracks: list[Track] = []
|
||||||
|
|
||||||
for trackhash in hash_set:
|
for trackhash in hash_set:
|
||||||
@@ -209,7 +208,7 @@ class TrackStore:
|
|||||||
tracks.append(track)
|
tracks.append(track)
|
||||||
|
|
||||||
# sort the tracks in the order of the given trackhashes
|
# sort the tracks in the order of the given trackhashes
|
||||||
if type(trackhashes) == list:
|
if type(trackhashes) is list:
|
||||||
tracks.sort(key=lambda t: trackhashes.index(t.trackhash))
|
tracks.sort(key=lambda t: trackhashes.index(t.trackhash))
|
||||||
|
|
||||||
return tracks
|
return tracks
|
||||||
|
|||||||
@@ -1047,7 +1047,7 @@ requires-dist = [
|
|||||||
{ name = "sortedcontainers", specifier = ">=2.4.0" },
|
{ name = "sortedcontainers", specifier = ">=2.4.0" },
|
||||||
{ name = "sqlalchemy", specifier = ">=2.0.31" },
|
{ name = "sqlalchemy", specifier = ">=2.0.31" },
|
||||||
{ name = "tabulate", specifier = ">=0.9.0" },
|
{ name = "tabulate", specifier = ">=0.9.0" },
|
||||||
{ name = "tinytag", specifier = ">=2.0.0" },
|
{ name = "tinytag", specifier = ">=2.1.1" },
|
||||||
{ name = "tqdm", specifier = ">=4.65.0" },
|
{ name = "tqdm", specifier = ">=4.65.0" },
|
||||||
{ name = "unidecode", specifier = ">=1.3.6" },
|
{ name = "unidecode", specifier = ">=1.3.6" },
|
||||||
{ name = "watchdog", specifier = ">=4.0.0" },
|
{ name = "watchdog", specifier = ">=4.0.0" },
|
||||||
@@ -1090,11 +1090,11 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tinytag"
|
name = "tinytag"
|
||||||
version = "2.1.0"
|
version = "2.1.1"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/c1/44/9818c9272fffb67fa2bf4804ce7cda538726238d9424e006772518ebacd0/tinytag-2.1.0.tar.gz", hash = "sha256:9a1b2e37aa45723541621133004ae86416086a0b1922e600cff5bfca5ef93e55", size = 35803 }
|
sdist = { url = "https://files.pythonhosted.org/packages/18/1e/90893a772800ef04ab337f5debf6adf976544d8e683bba9a26a376079814/tinytag-2.1.1.tar.gz", hash = "sha256:b417d480cf3b0c2d60a3afef705b29ac0080fc72d35b0b579b64184c54ee394c", size = 35860 }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/00/6e/6d258b355f78047b3aa1abd4c5a12fd3cd4b3d45774651fa90d3aea2e5a4/tinytag-2.1.0-py3-none-any.whl", hash = "sha256:1261c25f5dc0a192eb182c4d9ac5facb1e86ba03a005a1322ec545d06a78d719", size = 31057 },
|
{ url = "https://files.pythonhosted.org/packages/43/db/272d1b127d30107c1bb2724ba1d2aa7b75364824c7d203a84d8a8237fd6c/tinytag-2.1.1-py3-none-any.whl", hash = "sha256:b49da8f41dc0c457ecce32e6c5b2595aed8ac9314402192cd6cdb0fef67747eb", size = 31115 },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
Reference in New Issue
Block a user