From 378df938a0757f1ffc81bb548fbd459fc4f2d885 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Sat, 16 May 2026 11:19:26 +0200 Subject: [PATCH 1/2] Configure docker-compose.yaml for Synology NAS deployment Set timezone, user/group IDs, external port, and volume paths for a personal NAS music library setup on /volume1/docker/Music. Co-Authored-By: Claude Sonnet 4.6 --- docker/docker-compose.yaml | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml index b663c805..31bef057 100644 --- a/docker/docker-compose.yaml +++ b/docker/docker-compose.yaml @@ -3,20 +3,13 @@ services: image: pspitzner/beets-flask:stable restart: unless-stopped ports: - - "5001:5001" + - "5006:5001" environment: - # Change to your timezone - TZ: "Europe/Berlin" - # 502 is default on macos, 1000 on linux - USER_ID: 1000 - GROUP_ID: 1000 - # Optional: Add extra groups to the beetle user for file permissions - # Format: "group_name1:gid1,group_name2:gid2" - # Example: EXTRA_GROUPS: "nas_shares:1001,media:1002" + TZ: "Europe/Paris" + USER_ID: 1026 + GROUP_ID: 100 volumes: - - /wherever/config/:/config - # for music folders, match paths inside and out of container! - - /music_path/inbox/:/music_path/inbox/ - - /music_path/clean/:/music_path/clean/ - # If you want to persist the logs, you can mount a logs directory - # - /wherever/logs/:/logs + - /volume1/docker/Music/beets-flask/config:/config + # for music folders, paths match inside and out of container! + - /volume1/docker/Music/MusicToTag:/volume1/docker/Music/MusicToTag + - /volume1/docker/Music/Music:/volume1/docker/Music/Music From 8dd563f29806cdf752970c1ba005999ad436ceb4 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Sat, 16 May 2026 12:16:28 +0200 Subject: [PATCH 2/2] fix: add pytz to production dependencies pytz is imported at runtime in database/models/base.py but was only listed under typed (dev) extras as types-pytz. This caused a ModuleNotFoundError on startup in the stable Docker image. Co-Authored-By: Claude Sonnet 4.6 --- backend/pyproject.toml | 301 +++++++++++++++++++++-------------------- 1 file changed, 151 insertions(+), 150 deletions(-) diff --git a/backend/pyproject.toml b/backend/pyproject.toml index 2be7b33e..e1880ace 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -1,150 +1,151 @@ -[project] -name = "beets-flask" -description = "An opinionated web-interface around the music organizer [beets](https://beets.io/)" -version = "1.2.1" -authors = [ - { name = "F. Paul Spitzner", email = "paul.spitzner@gmail.com" }, - { name = "Sebastian B. Mohr", email = "sebastian@mohrenclan.de" }, -] -requires-python = ">= 3.11" -readme = "../README.md" -classifiers = [ - "Development Status :: 4 - Beta", - "Environment :: Web Environment", - "License :: OSI Approved :: MIT License", -] -dependencies = [ - "quart>=0.20.0", - "confuse>=2.0.1", - "beets==2.5.1", - "sqlalchemy>=2.0.35", - "rq>=2.0.0", - "watchdog>=5.0.3", - "requests>=2.32.3", - "python-socketio>=5.11.4", - "pillow>=10.4.0", - "cachetools>=5.3.3", - "libtmux>=0.37.0", - "Deprecated>=1.2.18", - "nest_asyncio>=1.6.0", - # Used for hosting the web-interface & api - "uvicorn>=0.36.0", - # beets plugin dependencies - "pylast>=5.2.0", - "python2ts>=0.6.1", - #"scantree>=0.0.4", - "natsort", - "tinytag", - "pydub", - "aiohttp", - "aiofiles", - "numpy", - "pandas", - "typing_extensions", -] - -[project.optional-dependencies] -# Can be install with e.g. `pip install -e .[dev]` -test = [ - "pytest>=8.2.2", - "pytest-asyncio>=0.23.8", - "pytest-cov>=5.0.0", - "fakeredis", -] -dev = ["ruff>=0.6.5", "pre-commit>=3.8.0", "beets_flask[typed]"] -typed = [ - "types-cachetools", - "types-requests", - "mypy>=1.14.1", - "types-cachetools", - "types-Deprecated", - "types-aiofiles", - "types-pytz", - "pandas-stubs", -] -all = ["beets_flask[dev,test]"] -docs = [ - "sphinx>=8.0.2", - "furo>=2024.8.6", - "sphinx-copybutton>=0.5.2", - "sphinx-inline-tabs>=2023.4.21", - "sphinxcontrib-typer[html]>=0.5.0", - "myst-parser>=4.0.0", - "myst-nb>=1.1.2", -] - -[build-system] -requires = ["hatchling"] -build-backend = "hatchling.build" - -[tool.hatch.build.targets.wheel] -package = "./beets_flask" -packages = ["beets_flask"] - -[tool.hatch.metadata] -allow-direct-references = true - -[tool.ruff] -include = ["pyproject.toml", "beets_flask/**/*.py", "tests/**/*.py"] -target-version = "py311" - -[tool.ruff.lint.per-file-ignores] -"**/tests/**/*" = ["D"] - - -[tool.ruff.lint] -select = [ - "I", - "D", - # Augment the convention by requiring an imperative mood for all docstrings. - "D401", - # Unused imports - "F401", - # pyupgrade - "UP", -] -ignore = [ - # Ignore req. for public facing functions docstrings - "D10", - "D401", - "D202", -] -fixable = ["ALL"] - -[tool.ruff.lint.pydocstyle] -convention = "numpy" - -[tool.ruff.lint.isort] -known-first-party = ["beets_flask"] - -[tool.pytest.ini_options] -# addopts = ["--import-mode=importlib", "--cov=beets_flask"] -addopts = ["--import-mode=importlib"] -filterwarnings = [ - "error", - "ignore::sqlalchemy.exc.SAWarning", - "ignore::DeprecationWarning", -] -pythonpath = ["."] -asyncio_mode = "auto" -log_format = "%(relativeCreated)-8d [%(levelname)-5s] %(name)s %(filename)-8s:%(lineno)d %(message)s" -asyncio_default_fixture_loop_scope = "function" - -[tool.coverage.report] -omit = ["*/tests/*"] - -[tool.mypy] -check_untyped_defs = true -disallow_untyped_decorators = true -allow_redefinition = true - -[[tool.mypy.overrides]] -# Suppresses error messages about imports that cannot be resolved. -module = [ - "socketio.*", - "confuse.*", - "mediafile.*", - "nest_asyncio", - "beetsplug.*", -] -ignore_missing_imports = true +[project] +name = "beets-flask" +description = "An opinionated web-interface around the music organizer [beets](https://beets.io/)" +version = "1.2.1" +authors = [ + { name = "F. Paul Spitzner", email = "paul.spitzner@gmail.com" }, + { name = "Sebastian B. Mohr", email = "sebastian@mohrenclan.de" }, +] +requires-python = ">= 3.11" +readme = "../README.md" +classifiers = [ + "Development Status :: 4 - Beta", + "Environment :: Web Environment", + "License :: OSI Approved :: MIT License", +] +dependencies = [ + "quart>=0.20.0", + "confuse>=2.0.1", + "beets==2.5.1", + "sqlalchemy>=2.0.35", + "rq>=2.0.0", + "watchdog>=5.0.3", + "requests>=2.32.3", + "python-socketio>=5.11.4", + "pillow>=10.4.0", + "cachetools>=5.3.3", + "libtmux>=0.37.0", + "Deprecated>=1.2.18", + "nest_asyncio>=1.6.0", + # Used for hosting the web-interface & api + "uvicorn>=0.36.0", + # beets plugin dependencies + "pylast>=5.2.0", + "python2ts>=0.6.1", + #"scantree>=0.0.4", + "natsort", + "tinytag", + "pydub", + "aiohttp", + "aiofiles", + "numpy", + "pandas", + "typing_extensions", + "pytz", +] + +[project.optional-dependencies] +# Can be install with e.g. `pip install -e .[dev]` +test = [ + "pytest>=8.2.2", + "pytest-asyncio>=0.23.8", + "pytest-cov>=5.0.0", + "fakeredis", +] +dev = ["ruff>=0.6.5", "pre-commit>=3.8.0", "beets_flask[typed]"] +typed = [ + "types-cachetools", + "types-requests", + "mypy>=1.14.1", + "types-cachetools", + "types-Deprecated", + "types-aiofiles", + "types-pytz", + "pandas-stubs", +] +all = ["beets_flask[dev,test]"] +docs = [ + "sphinx>=8.0.2", + "furo>=2024.8.6", + "sphinx-copybutton>=0.5.2", + "sphinx-inline-tabs>=2023.4.21", + "sphinxcontrib-typer[html]>=0.5.0", + "myst-parser>=4.0.0", + "myst-nb>=1.1.2", +] + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.hatch.build.targets.wheel] +package = "./beets_flask" +packages = ["beets_flask"] + +[tool.hatch.metadata] +allow-direct-references = true + +[tool.ruff] +include = ["pyproject.toml", "beets_flask/**/*.py", "tests/**/*.py"] +target-version = "py311" + +[tool.ruff.lint.per-file-ignores] +"**/tests/**/*" = ["D"] + + +[tool.ruff.lint] +select = [ + "I", + "D", + # Augment the convention by requiring an imperative mood for all docstrings. + "D401", + # Unused imports + "F401", + # pyupgrade + "UP", +] +ignore = [ + # Ignore req. for public facing functions docstrings + "D10", + "D401", + "D202", +] +fixable = ["ALL"] + +[tool.ruff.lint.pydocstyle] +convention = "numpy" + +[tool.ruff.lint.isort] +known-first-party = ["beets_flask"] + +[tool.pytest.ini_options] +# addopts = ["--import-mode=importlib", "--cov=beets_flask"] +addopts = ["--import-mode=importlib"] +filterwarnings = [ + "error", + "ignore::sqlalchemy.exc.SAWarning", + "ignore::DeprecationWarning", +] +pythonpath = ["."] +asyncio_mode = "auto" +log_format = "%(relativeCreated)-8d [%(levelname)-5s] %(name)s %(filename)-8s:%(lineno)d %(message)s" +asyncio_default_fixture_loop_scope = "function" + +[tool.coverage.report] +omit = ["*/tests/*"] + +[tool.mypy] +check_untyped_defs = true +disallow_untyped_decorators = true +allow_redefinition = true + +[[tool.mypy.overrides]] +# Suppresses error messages about imports that cannot be resolved. +module = [ + "socketio.*", + "confuse.*", + "mediafile.*", + "nest_asyncio", + "beetsplug.*", +] +ignore_missing_imports = true