1+ name : Linux Build AMD64
2+
3+ permissions :
4+ contents : write
5+
6+ on :
7+ push :
8+ branches : [ "main", "dev", "linux-*" ]
9+ tags :
10+ - " *"
11+ pull_request :
12+ branches : [ "main", "dev" ]
13+ workflow_dispatch :
14+
15+ jobs :
16+ build :
17+ runs-on : ubuntu-latest
18+
19+ steps :
20+ - name : Checkout code
21+ uses : actions/checkout@v4
22+ with :
23+ fetch-depth : 0
24+
25+ - name : Extract metadata
26+ id : meta
27+ shell : bash
28+ run : |
29+ if [[ "${{ github.ref }}" == refs/tags/* ]]; then
30+ echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
31+ echo "IS_TAG=true" >> $GITHUB_OUTPUT
32+ else
33+ echo "VERSION=$(cat version.txt)" >> $GITHUB_OUTPUT
34+ echo "BRANCH=${GITHUB_REF#refs/heads/}" >> $GITHUB_OUTPUT
35+ echo "IS_TAG=false" >> $GITHUB_OUTPUT
36+ fi
37+
38+ - name : Set up Python
39+ uses : actions/setup-python@v4
40+ with :
41+ python-version : ' 3.10'
42+
43+ - name : Install system dependencies
44+ run : |
45+ sudo apt-get update
46+ sudo apt-get install -y build-essential
47+
48+ - name : Install Python dependencies
49+ run : |
50+ python -m pip install --upgrade pip
51+ pip install -r requirements.txt
52+ pip install pyinstaller==6.1.0
53+ # Explicitly install apprise and dependencies
54+ pip install apprise==1.6.0
55+ pip install markdown==3.4.3
56+ pip install pyyaml==6.0
57+
58+ - name : Create PyInstaller spec for Linux
59+ run : |
60+ cat > Huntarr-linux.spec << 'EOF'
61+ # -*- mode: python ; coding: utf-8 -*-
62+ from PyInstaller.building.api import PYZ, EXE, COLLECT
63+ from PyInstaller.building.build_main import Analysis
64+ import os
65+
66+ block_cipher = None
67+
68+ datas = [
69+ ('frontend', 'frontend'),
70+ ('version.txt', '.'),
71+ ('README.md', '.'),
72+ ('LICENSE', '.'),
73+ ('src', 'src'),
74+ ]
75+
76+ # Add apprise data files
77+ try:
78+ import apprise
79+ apprise_path = os.path.dirname(apprise.__file__)
80+ apprise_attachment_path = os.path.join(apprise_path, 'attachment')
81+ apprise_plugins_path = os.path.join(apprise_path, 'plugins')
82+ apprise_config_path = os.path.join(apprise_path, 'config')
83+
84+ if os.path.exists(apprise_attachment_path):
85+ datas.append((apprise_attachment_path, 'apprise/attachment'))
86+ if os.path.exists(apprise_plugins_path):
87+ datas.append((apprise_plugins_path, 'apprise/plugins'))
88+ if os.path.exists(apprise_config_path):
89+ datas.append((apprise_config_path, 'apprise/config'))
90+ except ImportError:
91+ print("Warning: apprise not found, skipping apprise data files")
92+
93+ a = Analysis(
94+ ['main.py'],
95+ pathex=['.'],
96+ binaries=[],
97+ datas=datas,
98+ hiddenimports=[
99+ 'flask', 'flask.json', 'requests', 'waitress', 'bcrypt', 'qrcode', 'PIL',
100+ 'pyotp', 'qrcode.image.pil', 'routes', 'main', 'apprise', 'apprise.common',
101+ 'apprise.conversion', 'apprise.decorators', 'apprise.locale', 'apprise.logger',
102+ 'apprise.manager', 'apprise.utils', 'apprise.URLBase', 'apprise.AppriseAsset',
103+ 'apprise.AppriseAttachment', 'apprise.AppriseConfig', 'apprise.cli',
104+ 'apprise.config', 'apprise.attachment', 'apprise.plugins', 'markdown', 'yaml', 'cryptography',
105+ ],
106+ hookspath=[],
107+ hooksconfig={},
108+ runtime_hooks=[],
109+ excludes=[],
110+ cipher=block_cipher,
111+ noarchive=False,
112+ )
113+
114+ pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
115+
116+ exe = EXE(
117+ pyz, a.scripts, a.binaries, a.zipfiles, a.datas, [],
118+ name='huntarr', debug=False, bootloader_ignore_signals=False,
119+ strip=False, upx=True, upx_exclude=[], runtime_tmpdir=None,
120+ console=True, disable_windowed_traceback=False,
121+ )
122+ EOF
123+
124+ - name : Build Linux executable
125+ run : |
126+ # Build Linux executable
127+ python -m PyInstaller Huntarr-linux.spec --clean
128+
129+ # Verify the executable was created
130+ ls -la dist/
131+ file dist/huntarr
132+
133+ # Test that it's executable
134+ chmod +x dist/huntarr
135+
136+ - name : Create distribution package
137+ run : |
138+ # Create distribution directory
139+ mkdir -p dist/huntarr-linux-amd64
140+
141+ # Copy executable
142+ cp dist/huntarr dist/huntarr-linux-amd64/
143+
144+ # Create startup script
145+ cat > dist/huntarr-linux-amd64/start-huntarr.sh << 'EOF'
146+ #!/bin/bash
147+ # Huntarr Linux Startup Script
148+
149+ # Get the directory where this script is located
150+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
151+ cd "$SCRIPT_DIR"
152+
153+ # Set up config directory in user's home
154+ export HUNTARR_CONFIG_DIR="$HOME/.config/huntarr"
155+ mkdir -p "$HUNTARR_CONFIG_DIR"
156+
157+ # Set permissions
158+ chmod -R 755 "$HUNTARR_CONFIG_DIR" 2>/dev/null || true
159+
160+ echo "Starting Huntarr..."
161+ echo "Config directory: $HUNTARR_CONFIG_DIR"
162+ echo "Web interface will be available at: http://localhost:9705"
163+ echo ""
164+
165+ # Start Huntarr
166+ ./huntarr
167+ EOF
168+
169+ chmod +x dist/huntarr-linux-amd64/start-huntarr.sh
170+
171+ # Create README
172+ cat > dist/huntarr-linux-amd64/README.txt << 'EOF'
173+ Huntarr Linux AMD64 Distribution
174+ ================================
175+
176+ Installation:
177+ 1. Extract this archive to your desired location
178+ 2. Run: ./start-huntarr.sh
179+ 3. Open your browser to: http://localhost:9705
180+
181+ Files:
182+ - huntarr: Main executable
183+ - start-huntarr.sh: Startup script (recommended)
184+ - README.txt: This file
185+
186+ Configuration:
187+ - Config files will be stored in: ~/.config/huntarr/
188+ - Logs are stored in the database (no separate log files)
189+
190+ Requirements:
191+ - Linux AMD64 (x86_64) system
192+ - No additional dependencies required (all bundled)
193+
194+ Support:
195+ - GitHub: https://github.com/plexguide/Huntarr.io
196+ - Documentation: https://plexguide.github.io/Huntarr.io/
197+ EOF
198+
199+ # Copy license and version info
200+ cp LICENSE dist/huntarr-linux-amd64/ 2>/dev/null || true
201+ cp version.txt dist/huntarr-linux-amd64/ 2>/dev/null || true
202+
203+ # Show contents
204+ ls -la dist/huntarr-linux-amd64/
205+
206+ - name : Create archive
207+ run : |
208+ version="${{ steps.meta.outputs.VERSION }}"
209+
210+ if [[ "${{ steps.meta.outputs.IS_TAG }}" == "true" ]]; then
211+ archive_name="Huntarr-${version}-linux-amd64.tar.gz"
212+ else
213+ branch="${{ steps.meta.outputs.BRANCH }}"
214+ branch_safe=$(echo "${branch}" | tr '/' '-')
215+ archive_name="Huntarr-${version}-linux-${branch_safe}-amd64.tar.gz"
216+ fi
217+
218+ cd dist
219+ tar -czf "../${archive_name}" huntarr-linux-amd64/
220+ cd ..
221+
222+ # Verify archive
223+ echo "Created archive: ${archive_name}"
224+ ls -lh "${archive_name}"
225+ tar -tzf "${archive_name}" | head -10
226+
227+ - name : Upload artifacts
228+ uses : actions/upload-artifact@v4
229+ with :
230+ name : huntarr-linux-amd64
231+ path : ' *.tar.gz'
232+ retention-days : 30
233+
234+ - name : Upload to release
235+ if : steps.meta.outputs.IS_TAG == 'true'
236+ uses : softprops/action-gh-release@v1
237+ with :
238+ files : ' *.tar.gz'
239+ env :
240+ GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
0 commit comments