mirror of
https://github.com/Dvorinka/swingmusic-extended.git
synced 2026-06-03 20:13:02 +00:00
fix client: download fallback to github release client
+ add fallback release version data to version.txt + move classproperty class to utils + update Dockerfile to install from source using pip install + move version info to Metadata class in settings.py
This commit is contained in:
@@ -193,6 +193,9 @@ jobs:
|
|||||||
- name: Checkout into repo
|
- name: Checkout into repo
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Create version.txt
|
||||||
|
run: echo ${{ github.event.inputs.tag }} > version.txt
|
||||||
|
|
||||||
- name: Download artifact
|
- name: Download artifact
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
|
|
||||||
|
|||||||
+12
-11
@@ -1,21 +1,22 @@
|
|||||||
FROM python:3.11-slim
|
FROM python:3.11-slim
|
||||||
WORKDIR /app/swingmusic
|
WORKDIR /app
|
||||||
|
|
||||||
# Copy the files in the current dir into the container
|
|
||||||
# copy wheelhouse and client
|
|
||||||
COPY wheels wheels
|
|
||||||
|
|
||||||
|
|
||||||
LABEL "author"="swing music"
|
LABEL "author"="swing music"
|
||||||
EXPOSE 1970/tcp
|
EXPOSE 1970/tcp
|
||||||
VOLUME /music
|
VOLUME /music
|
||||||
VOLUME /config
|
VOLUME /config
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y gcc git libev-dev python3-dev ffmpeg libavcodec-extra && \
|
RUN apt-get update
|
||||||
apt-get clean && \
|
|
||||||
rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
RUN pip install --no-cache-dir --find-links=wheels/ swingmusic
|
RUN apt-get install -y gcc libev-dev
|
||||||
Run rm -rf /app/swingmusic/wheels
|
RUN apt-get install -y ffmpeg libavcodec-extra
|
||||||
|
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Copy repo root files needed for installation
|
||||||
|
COPY pyproject.toml requirements.txt version.txt ./
|
||||||
|
COPY src/ ./src/
|
||||||
|
|
||||||
|
# Install the package and its dependencies
|
||||||
|
RUN pip install --no-cache-dir .
|
||||||
|
|
||||||
ENTRYPOINT ["python", "-m", "swingmusic", "--host", "0.0.0.0", "--config", "/config"]
|
ENTRYPOINT ["python", "-m", "swingmusic", "--host", "0.0.0.0", "--config", "/config"]
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
from dataclasses import asdict
|
from dataclasses import asdict
|
||||||
from importlib import metadata
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from flask_openapi3 import Tag
|
from flask_openapi3 import Tag
|
||||||
from flask_openapi3 import APIBlueprint
|
from flask_openapi3 import APIBlueprint
|
||||||
@@ -9,6 +8,7 @@ from swingmusic.api.auth import admin_required
|
|||||||
from swingmusic.db.userdata import PluginTable
|
from swingmusic.db.userdata import PluginTable
|
||||||
from swingmusic.lib.index import index_everything
|
from swingmusic.lib.index import index_everything
|
||||||
from swingmusic.config import UserConfig
|
from swingmusic.config import UserConfig
|
||||||
|
from swingmusic.settings import Metadata
|
||||||
from swingmusic.utils.auth import get_current_userid
|
from swingmusic.utils.auth import get_current_userid
|
||||||
|
|
||||||
bp_tag = Tag(name="Settings", description="Customize stuff")
|
bp_tag = Tag(name="Settings", description="Customize stuff")
|
||||||
@@ -102,7 +102,11 @@ def get_all_settings():
|
|||||||
config[key] = sorted(list(value))
|
config[key] = sorted(list(value))
|
||||||
|
|
||||||
config["plugins"] = [p for p in PluginTable.get_all()]
|
config["plugins"] = [p for p in PluginTable.get_all()]
|
||||||
config["version"] = metadata.version("swingmusic")
|
config["version"] = Metadata.version
|
||||||
|
|
||||||
|
if config["version"] == "0.0.0":
|
||||||
|
# fallback to version.txt (useful for docker builds)
|
||||||
|
config["version"] = open("version.txt", "r").read().strip()
|
||||||
|
|
||||||
# only return lastfmSessionKey for the current user
|
# only return lastfmSessionKey for the current user
|
||||||
current_user = get_current_userid()
|
current_user = get_current_userid()
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
from importlib import metadata
|
|
||||||
import datetime as dt
|
import datetime as dt
|
||||||
import pathlib
|
import pathlib
|
||||||
import logging
|
import logging
|
||||||
@@ -13,7 +12,7 @@ from flask_jwt_extended import JWTManager, create_access_token, get_jwt, get_jwt
|
|||||||
from swingmusic import api as swing_api
|
from swingmusic import api as swing_api
|
||||||
from swingmusic.config import UserConfig
|
from swingmusic.config import UserConfig
|
||||||
from swingmusic.db.userdata import UserTable
|
from swingmusic.db.userdata import UserTable
|
||||||
from swingmusic.settings import Paths
|
from swingmusic.settings import Metadata, Paths
|
||||||
from swingmusic.utils.paths import get_client_files_extensions
|
from swingmusic.utils.paths import get_client_files_extensions
|
||||||
|
|
||||||
from swingmusic.api.plugins import lyrics as lyrics_plugin
|
from swingmusic.api.plugins import lyrics as lyrics_plugin
|
||||||
@@ -102,7 +101,7 @@ def load_plugins(web: OpenAPI):
|
|||||||
|
|
||||||
api_info = Info(
|
api_info = Info(
|
||||||
title="Swing Music",
|
title="Swing Music",
|
||||||
version=f"v{metadata.version('swingmusic')}",
|
version=f"v{Metadata.version}",
|
||||||
description="The REST API exposed by your Swing Music server",
|
description="The REST API exposed by your Swing Music server",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+35
-18
@@ -16,7 +16,9 @@ from pathlib import Path
|
|||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
import requests
|
import requests
|
||||||
from importlib import resources as imres
|
from importlib import metadata, resources as imres
|
||||||
|
|
||||||
|
from swingmusic.utils import classproperty
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
@@ -45,9 +47,7 @@ class AssetHandler:
|
|||||||
Handles all assets configuration
|
Handles all assets configuration
|
||||||
"""
|
"""
|
||||||
|
|
||||||
CLIENT_RELEASES_URL = (
|
RELEASES_URL = "https://api.github.com/repos/swingmx/swingmusic/releases"
|
||||||
"https://api.github.com/repos/swingmx/swingmusic/releases/latest"
|
|
||||||
)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def copy_assets_dir():
|
def copy_assets_dir():
|
||||||
@@ -104,20 +104,25 @@ class AssetHandler:
|
|||||||
Downloads the latest supported client from Github
|
Downloads the latest supported client from Github
|
||||||
and places it in the swingmusic client folder.
|
and places it in the swingmusic client folder.
|
||||||
"""
|
"""
|
||||||
path = Paths().config_parent / "client"
|
log.error("Default client not found. Downloading from GitHub ...")
|
||||||
|
path = Paths().client_path
|
||||||
|
|
||||||
try:
|
try:
|
||||||
answer = requests.get(AssetHandler.CLIENT_RELEASES_URL).json()
|
# INFO: downlaod the current version of the client from GitHub
|
||||||
|
releases = requests.get(AssetHandler.RELEASES_URL).json()
|
||||||
|
|
||||||
for asset in answer["assets"]:
|
# INFO: find the release for the current version
|
||||||
|
for release in releases:
|
||||||
|
if release["tag_name"] == f"v{Metadata.version}":
|
||||||
|
# INFO: find the client.zip asset
|
||||||
|
for asset in release["assets"]:
|
||||||
if asset["name"] == "client.zip":
|
if asset["name"] == "client.zip":
|
||||||
# download and convert client
|
# download and extract client
|
||||||
client = requests.get(asset["browser_download_url"])
|
clientzip = requests.get(asset["browser_download_url"])
|
||||||
mem_file = io.BytesIO(client.content)
|
mem_file = io.BytesIO(clientzip.content)
|
||||||
file = zipfile.ZipFile(mem_file)
|
file = zipfile.ZipFile(mem_file)
|
||||||
|
|
||||||
# create new dir for extraction
|
# create new dir for extraction
|
||||||
log.info(f"Storing client in '{path.as_posix()}'.")
|
|
||||||
with tempfile.TemporaryDirectory() as temp_folder:
|
with tempfile.TemporaryDirectory() as temp_folder:
|
||||||
file.extractall(temp_folder)
|
file.extractall(temp_folder)
|
||||||
|
|
||||||
@@ -128,6 +133,8 @@ class AssetHandler:
|
|||||||
dirs_exist_ok=True,
|
dirs_exist_ok=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
log.info("Client downloaded successfully.")
|
||||||
|
break
|
||||||
break
|
break
|
||||||
|
|
||||||
except (
|
except (
|
||||||
@@ -140,12 +147,6 @@ class AssetHandler:
|
|||||||
exc_info=e,
|
exc_info=e,
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
except requests.exceptions.InvalidJSONError as e:
|
|
||||||
log.error(
|
|
||||||
"Client could not be downloaded from releases. JSON ERROR",
|
|
||||||
exc_info=e,
|
|
||||||
)
|
|
||||||
return False
|
|
||||||
except zipfile.BadZipfile as e:
|
except zipfile.BadZipfile as e:
|
||||||
log.error("Client could not be unpacked. ZIP ERROR", exc_info=e)
|
log.error("Client could not be unpacked. ZIP ERROR", exc_info=e)
|
||||||
return False
|
return False
|
||||||
@@ -155,8 +156,9 @@ class AssetHandler:
|
|||||||
"""
|
"""
|
||||||
Runs on startup to ensure the default client is present.
|
Runs on startup to ensure the default client is present.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
extracted = True
|
||||||
client_path = Paths().client_path
|
client_path = Paths().client_path
|
||||||
extracted = False
|
|
||||||
|
|
||||||
if not client_path.exists() or not (client_path / "index.html").exists():
|
if not client_path.exists() or not (client_path / "index.html").exists():
|
||||||
extracted = cls.extract_default_client(Paths().config_dir)
|
extracted = cls.extract_default_client(Paths().config_dir)
|
||||||
@@ -504,3 +506,18 @@ class TCOLOR:
|
|||||||
BOLD = "\033[1m"
|
BOLD = "\033[1m"
|
||||||
UNDERLINE = "\033[4m"
|
UNDERLINE = "\033[4m"
|
||||||
# credits: https://stackoverflow.com/a/287944
|
# credits: https://stackoverflow.com/a/287944
|
||||||
|
|
||||||
|
|
||||||
|
class Metadata:
|
||||||
|
"""
|
||||||
|
Contains metadata for the application.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@classproperty
|
||||||
|
def version(self) -> str:
|
||||||
|
version = metadata.version("swingmusic")
|
||||||
|
|
||||||
|
if version == "0.0.0":
|
||||||
|
return open("version.txt", "r").read().strip()
|
||||||
|
|
||||||
|
return version
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
from swingmusic.settings import TCOLOR, Paths
|
from swingmusic.settings import TCOLOR, Metadata, Paths
|
||||||
from swingmusic.utils.network import get_ip
|
from swingmusic.utils.network import get_ip
|
||||||
from importlib import metadata
|
|
||||||
|
|
||||||
|
|
||||||
def log_startup_info(host: str, port: int):
|
def log_startup_info(host: str, port: int):
|
||||||
print(f"{TCOLOR.HEADER}Swing Music v{metadata.version('swingmusic')} {TCOLOR.ENDC}")
|
print(f"{TCOLOR.HEADER}Swing Music v{Metadata.version} {TCOLOR.ENDC}")
|
||||||
|
|
||||||
addresses = [host]
|
addresses = [host]
|
||||||
|
|
||||||
@@ -14,8 +13,6 @@ def log_startup_info(host: str, port: int):
|
|||||||
|
|
||||||
print("Server running on:\n")
|
print("Server running on:\n")
|
||||||
for address in addresses:
|
for address in addresses:
|
||||||
print(
|
print(f"{TCOLOR.OKGREEN}http://{address}:{port}{TCOLOR.ENDC}")
|
||||||
f"{TCOLOR.OKGREEN}http://{address}:{port}{TCOLOR.ENDC}"
|
|
||||||
)
|
|
||||||
|
|
||||||
print(f"\n{TCOLOR.YELLOW}Data folder: {Paths().config_dir}{TCOLOR.ENDC}\n")
|
print(f"\n{TCOLOR.YELLOW}Data folder: {Paths().config_dir}{TCOLOR.ENDC}\n")
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import socket
|
import socket
|
||||||
import sys
|
|
||||||
from swingmusic import app_builder
|
from swingmusic import app_builder
|
||||||
from swingmusic.crons import start_cron_jobs
|
from swingmusic.crons import start_cron_jobs
|
||||||
from swingmusic.plugins.register import register_plugins
|
from swingmusic.plugins.register import register_plugins
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ from typing import Callable, Iterable
|
|||||||
from swingmusic.db.libdata import TrackTable
|
from swingmusic.db.libdata import TrackTable
|
||||||
|
|
||||||
from swingmusic.models import Track
|
from swingmusic.models import Track
|
||||||
|
from swingmusic.utils import classproperty
|
||||||
from swingmusic.utils.auth import get_current_userid
|
from swingmusic.utils.auth import get_current_userid
|
||||||
from swingmusic.utils.remove_duplicates import remove_duplicates
|
from swingmusic.utils.remove_duplicates import remove_duplicates
|
||||||
|
|
||||||
@@ -61,14 +62,7 @@ class TrackGroup:
|
|||||||
return len(self.tracks)
|
return len(self.tracks)
|
||||||
|
|
||||||
|
|
||||||
class classproperty(property):
|
|
||||||
"""
|
|
||||||
A class property decorator.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __get__(self, owner_self, owner_cls):
|
|
||||||
if self.fget:
|
|
||||||
return self.fget(owner_cls)
|
|
||||||
|
|
||||||
|
|
||||||
class TrackStore:
|
class TrackStore:
|
||||||
|
|||||||
@@ -19,3 +19,13 @@ def flatten(list_: Iterable[list[T]]) -> list[T]:
|
|||||||
Flattens a list of lists into a single list.
|
Flattens a list of lists into a single list.
|
||||||
"""
|
"""
|
||||||
return [item for sublist in list_ for item in sublist]
|
return [item for sublist in list_ for item in sublist]
|
||||||
|
|
||||||
|
|
||||||
|
class classproperty(property):
|
||||||
|
"""
|
||||||
|
A class property decorator.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __get__(self, owner_self, owner_cls):
|
||||||
|
if self.fget:
|
||||||
|
return self.fget(owner_cls)
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
2.1.0
|
||||||
Reference in New Issue
Block a user