music-assistant-home-assistant-addon

7.6 KBSH
entrypoint.sh
7.6 KB239 lines • bash
1#!/bin/sh
2set -e
3
4# Parse configuration
5server_repo=$(cat /data/options.json | jq -r .server_repo)
6frontend_repo=$(cat /data/options.json | jq -r .frontend_repo)
7
8echo ""
9echo "-----------------------------------------------------------"
10echo "Music Assistant Developer Add-on"
11echo "-----------------------------------------------------------"
12echo ""
13
14# Check if server_repo is empty or null
15if [ -z "$server_repo" ] || [ "$server_repo" = "null" ]; then
16    build_from_source=false
17    echo "No server_repo specified - using latest nightly release from GitHub"
18else
19    build_from_source=true
20    echo "Building from source using server_repo: $server_repo"
21fi
22echo ""
23
24# Function to parse repository reference and return owner/repo@ref
25parse_repo_ref() {
26    local input="$1"
27    local default_owner="$2"
28    local default_repo="$3"
29
30    # If input starts with "pr-", convert to pull request reference
31    if echo "$input" | grep -q "^pr-"; then
32        pr_number=$(echo "$input" | sed 's/pr-//')
33        echo "${default_owner}/${default_repo}@refs/pull/${pr_number}/head"
34        return
35    fi
36
37    # If input contains "/" (fork reference)
38    if echo "$input" | grep -q "/"; then
39        # Check if it already has @ for branch
40        if echo "$input" | grep -q "@"; then
41            echo "$input"
42        else
43            # It's just owner/repo, use default branch
44            echo "${input}@main"
45        fi
46        return
47    fi
48
49    # Otherwise, it's just a branch/commit reference
50    echo "${default_owner}/${default_repo}@${input}"
51}
52
53# Function to build git URL from parsed reference
54build_git_url() {
55    local parsed="$1"
56    echo "git+https://github.com/${parsed}"
57}
58
59# Activate virtual environment
60. $VIRTUAL_ENV/bin/activate
61
62echo "-----------------------------------------------------------"
63echo "Step 1: Installing Music Assistant Server"
64echo "-----------------------------------------------------------"
65echo ""
66
67if [ "$build_from_source" = true ]; then
68    # Parse server repository reference
69    server_ref=$(parse_repo_ref "$server_repo" "music-assistant" "server")
70    server_url=$(build_git_url "$server_ref")
71
72    echo "Server repository: $server_ref"
73    echo "Server URL: $server_url"
74    echo ""
75
76    # Build requirements URL from the same reference
77    # Convert git reference to raw GitHub URL for requirements file
78    # Format: owner/repo@ref -> https://raw.githubusercontent.com/owner/repo/ref/requirements_all.txt
79    req_owner=$(echo "$server_ref" | cut -d'/' -f1)
80    req_repo=$(echo "$server_ref" | cut -d'/' -f2 | cut -d'@' -f1)
81    req_ref=$(echo "$server_ref" | cut -d'@' -f2)
82    requirements_url="https://raw.githubusercontent.com/${req_owner}/${req_repo}/${req_ref}/requirements_all.txt"
83
84    echo "Installing dependencies from: $requirements_url"
85    echo ""
86
87    # Install dependencies from the branch's requirements_all.txt
88    uv pip install \
89        --no-cache \
90        --link-mode=copy \
91        -r "$requirements_url"
92
93    echo "✓ Dependencies installed"
94    echo ""
95
96    # Install server from specified repository
97    uv pip install \
98        --no-cache \
99        --link-mode=copy \
100        "$server_url"
101else
102    # Install latest nightly wheel from GitHub releases
103    echo "Fetching latest nightly release from GitHub..."
104    echo ""
105
106    # Get the latest pre-release info from GitHub API
107    # Write to temp file to avoid control character issues when passing through shell variables
108    tmp_releases="/tmp/releases.json"
109    curl -s "https://api.github.com/repos/music-assistant/server/releases?per_page=10" > "$tmp_releases"
110    release_tag=$(jq -r '[.[] | select(.prerelease == true)] | first | .tag_name' < "$tmp_releases")
111    wheel_url=$(jq -r '[.[] | select(.prerelease == true)] | first | .assets[] | select(.name | endswith(".whl")) | .browser_download_url' < "$tmp_releases")
112    rm -f "$tmp_releases"
113
114    if [ -z "$wheel_url" ] || [ "$wheel_url" = "null" ]; then
115        echo "ERROR: Could not find wheel in latest nightly release"
116        echo "Falling back to stable PyPI release..."
117        uv pip install \
118            --no-cache \
119            --link-mode=copy \
120            music-assistant
121    else
122        echo "Found nightly release: $release_tag"
123        echo "Wheel URL: $wheel_url"
124        echo ""
125        echo "Downloading and installing nightly wheel..."
126        uv pip install \
127            --no-cache \
128            --link-mode=copy \
129            "$wheel_url"
130    fi
131fi
132
133echo ""
134echo "✓ Server installation complete"
135echo ""
136
137# Check if we should build frontend - this is independent of server source
138build_frontend=false
139if [ -n "$frontend_repo" ] && [ "$frontend_repo" != "null" ]; then
140    build_frontend=true
141    # Parse frontend repository reference
142    frontend_ref=$(parse_repo_ref "$frontend_repo" "music-assistant" "frontend")
143
144    echo "-----------------------------------------------------------"
145    echo "Step 2: Building and Installing Music Assistant Frontend"
146    echo "-----------------------------------------------------------"
147    echo ""
148    echo "Frontend repository: $frontend_ref"
149    echo ""
150else
151    echo "-----------------------------------------------------------"
152    echo "Step 2: Skipping Frontend Build"
153    echo "-----------------------------------------------------------"
154    echo ""
155    echo "No frontend_repo specified - using frontend bundled with server"
156    echo ""
157fi
158
159if [ "$build_frontend" = true ]; then
160
161# Extract owner, repo, and ref from parsed reference
162frontend_owner=$(echo "$frontend_ref" | cut -d'/' -f1)
163frontend_repo_name=$(echo "$frontend_ref" | cut -d'/' -f2 | cut -d'@' -f1)
164frontend_branch=$(echo "$frontend_ref" | cut -d'@' -f2)
165
166# Create temporary directory for frontend build
167frontend_dir="/tmp/frontend-build"
168rm -rf "$frontend_dir"
169mkdir -p "$frontend_dir"
170
171echo "Cloning frontend repository..."
172cd "$frontend_dir"
173
174# Clone the repository
175git clone --depth 1 --branch "$frontend_branch" \
176    "https://github.com/${frontend_owner}/${frontend_repo_name}.git" . 2>/dev/null || \
177    git clone "https://github.com/${frontend_owner}/${frontend_repo_name}.git" . && \
178    git checkout "$frontend_branch"
179
180echo "✓ Frontend cloned"
181echo ""
182
183# Check if package.json exists (verify it's a valid frontend repo)
184if [ ! -f "package.json" ]; then
185    echo "ERROR: package.json not found in frontend repository!"
186    echo "This doesn't appear to be a valid Music Assistant frontend repository."
187    exit 1
188fi
189
190echo "Installing frontend dependencies...1"
191# Try to remount /tmp with exec if it's mounted noexec
192if mount | grep -q "on /tmp.*noexec"; then
193  echo "Detected /tmp mounted with noexec, attempting to remount..."
194  mount -o remount,exec /tmp 2>/dev/null || echo "Warning: Could not remount /tmp"
195fi
196yarn install --frozen-lockfile --prefer-offline
197
198echo "✓ Dependencies installed"
199echo ""
200
201echo "Building frontend..."
202yarn build
203
204echo "✓ Frontend build complete"
205echo ""
206
207# Check if the Python package structure exists
208if [ ! -f "setup.py" ] && [ ! -f "pyproject.toml" ]; then
209    echo "ERROR: No Python package configuration found!"
210    echo "Frontend repository must be installable as a Python package."
211    exit 1
212fi
213
214echo "Installing frontend as Python package..."
215cd "$frontend_dir"
216uv pip install --no-cache --link-mode=copy .
217
218echo "✓ Frontend installation complete"
219echo ""
220
221# Cleanup
222cd /
223rm -rf "$frontend_dir"
224
225fi  # End of build_frontend check
226
227echo "-----------------------------------------------------------"
228echo "Starting Music Assistant"
229echo "-----------------------------------------------------------"
230echo ""
231
232# export jemalloc path
233for path in /usr/lib/*/libjemalloc.so.2; do
234    [ -f "$path" ] && export LD_PRELOAD="$path" && break
235done
236# Start Music Assistant
237exec mass --data-dir /data --cache-dir /data/.cache
238
239