Skip to content

Commit ad49e7f

Browse files
committed
feat: App image build
1 parent f406b09 commit ad49e7f

4 files changed

Lines changed: 152 additions & 10 deletions

File tree

.github/workflows/release.yml

Lines changed: 83 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,12 +92,88 @@ jobs:
9292
cd build
9393
cmake --build . --config Release -j$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 2)
9494
95-
- name: Upload artifact
95+
- name: Create AppImage (Linux only)
96+
if: matrix.target == 'linux-x64'
97+
run: |
98+
set -e
99+
mkdir -p AppDir/usr/bin
100+
cp build/tuisic AppDir/usr/bin/
101+
102+
mkdir -p AppDir/usr/share/applications
103+
printf '%s\n' \
104+
'[Desktop Entry]' \
105+
'Name=Tuisic' \
106+
'Exec=tuisic' \
107+
'Icon=tuisic' \
108+
'Type=Application' \
109+
'Categories=Utility;' \
110+
'Terminal=true' \
111+
> AppDir/usr/share/applications/tuisic.desktop
112+
113+
printf '%s\n' \
114+
'import struct, zlib, os' \
115+
'C = (63, 185, 80)' \
116+
'def png(w, h, C):' \
117+
' def ch(ct, d):' \
118+
' p = ct + d' \
119+
' return struct.pack(">I", len(d)) + p + struct.pack(">I", zlib.crc32(p) & 0xffffffff)' \
120+
' r = b""' \
121+
' for y in range(h):' \
122+
' r += b"\x00" + bytes(C) * w' \
123+
' return b"\x89PNG\r\n\x1a\n" + ch(b"IHDR", struct.pack(">IIBBBBB", w, h, 8, 2, 0, 0, 0)) + ch(b"IDAT", zlib.compress(r)) + ch(b"IEND", b"")' \
124+
'for s in [48, 64, 128, 256, 512]:' \
125+
' d = "AppDir/usr/share/icons/hicolor/{0}x{0}/apps".format(s)' \
126+
' os.makedirs(d, exist_ok=True)' \
127+
' with open(d + "/tuisic.png", "wb") as f:' \
128+
' f.write(png(s, s, C))' \
129+
> /tmp/genicons.py
130+
python3 /tmp/genicons.py
131+
132+
cp AppDir/usr/share/icons/hicolor/256x256/apps/tuisic.png AppDir/tuisic.png
133+
cp AppDir/usr/share/icons/hicolor/256x256/apps/tuisic.png AppDir/.DirIcon
134+
135+
# Download and extract linuxdeploy (populates AppDir with libs)
136+
wget -q https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
137+
chmod +x linuxdeploy-x86_64.AppImage
138+
./linuxdeploy-x86_64.AppImage --appimage-extract
139+
mv squashfs-root linuxdeploy-app
140+
141+
./linuxdeploy-app/AppRun --appdir AppDir \
142+
-d AppDir/usr/share/applications/tuisic.desktop \
143+
-i AppDir/usr/share/icons/hicolor/256x256/apps/tuisic.png
144+
145+
# Create AppRun entrypoint
146+
cat > AppDir/AppRun << 'EOF'
147+
#!/bin/bash
148+
HERE="$(dirname "$(readlink -f "$0")")"
149+
exec "$HERE/usr/bin/tuisic" "$@"
150+
EOF
151+
chmod +x AppDir/AppRun
152+
153+
# Download appimagetool and create the AppImage
154+
wget -q https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage
155+
chmod +x appimagetool-x86_64.AppImage
156+
./appimagetool-x86_64.AppImage --appimage-extract
157+
mv squashfs-root appimagetool-app
158+
159+
ARCH=x86_64 VERSION=1.0.0 ./appimagetool-app/AppRun \
160+
AppDir tuisic-linux-x64.AppImage
161+
162+
ls -lh tuisic-linux-x64.AppImage
163+
164+
- name: Upload binary artifact
96165
uses: actions/upload-artifact@v4
97166
with:
98167
name: ${{ matrix.asset_name }}
99168
path: build/${{ matrix.artifact_name }}
100169

170+
- name: Upload AppImage artifact (Linux only)
171+
if: matrix.target == 'linux-x64'
172+
uses: actions/upload-artifact@v4
173+
with:
174+
name: tuisic-linux-x64.AppImage
175+
path: tuisic-linux-x64.AppImage
176+
101177
release:
102178
needs: build
103179
runs-on: ubuntu-latest
@@ -114,14 +190,15 @@ jobs:
114190

115191
- name: Prepare release assets
116192
run: |
117-
# Rename artifacts to have unique names with platform identifiers
118193
mkdir -p release-assets
119194
mv artifacts/tuisic-linux-x64/tuisic release-assets/tuisic-linux-x64
120195
mv artifacts/tuisic-macos-x64/tuisic release-assets/tuisic-macos-x64
121196
mv artifacts/tuisic-macos-arm64/tuisic release-assets/tuisic-macos-arm64
122-
# Make all binaries executable
197+
# Move AppImage if present
198+
if [ -f artifacts/tuisic-linux-x64.AppImage/tuisic-linux-x64.AppImage ]; then
199+
mv artifacts/tuisic-linux-x64.AppImage/tuisic-linux-x64.AppImage release-assets/tuisic-linux-x64.AppImage
200+
fi
123201
chmod +x release-assets/*
124-
# List files for debugging
125202
ls -lh release-assets/
126203
127204
- name: Generate changelog
@@ -154,11 +231,12 @@ jobs:
154231
155232
## Downloads
156233
Download the appropriate binary for your platform:
157-
- **Linux (x64)**: tuisic-linux-x64
234+
- **Linux (x64)**: tuisic-linux-x64 *(dynamic)* or **tuisic-linux-x64.AppImage** *(portable)*
158235
- **macOS (Intel)**: tuisic-macos-x64
159236
- **macOS (Apple Silicon)**: tuisic-macos-arm64
160237
files: |
161238
release-assets/tuisic-linux-x64
239+
release-assets/tuisic-linux-x64.AppImage
162240
release-assets/tuisic-macos-x64
163241
release-assets/tuisic-macos-arm64
164242
draft: false

TODO.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,5 @@
1010
- [X] Expose to MPRIS dbus
1111
- [X] Discord Rich Presence
1212
- [ ] Customizable Ascii Art in place of visualizer
13+
- [ ] Customizable theme
14+
- [X] AppImage

docs/favicon.ico

3.28 KB
Binary file not shown.

docs/index.html

Lines changed: 67 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
<meta charset="UTF-8">
55
<meta name="viewport" content="width=device-width, initial-scale=1.0">
66
<title>tuisic — TUI Music Streaming</title>
7+
<link rel="icon" type="image/x-icon" href="favicon.ico">
78
<link rel="preconnect" href="https://fonts.googleapis.com">
89
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet">
910
<style>
@@ -500,6 +501,38 @@
500501
color: #c8d8c8;
501502
}
502503

504+
.code-block-wrap {
505+
position: relative;
506+
}
507+
508+
.copy-btn {
509+
position: absolute;
510+
top: 8px;
511+
right: 8px;
512+
background: rgba(255, 255, 255, 0.06);
513+
border: 1px solid rgba(255, 255, 255, 0.08);
514+
color: #6b7a6b;
515+
font-family: 'JetBrains Mono', monospace;
516+
font-size: 11px;
517+
padding: 4px 10px;
518+
border-radius: 5px;
519+
cursor: pointer;
520+
transition: all .2s;
521+
z-index: 1;
522+
}
523+
524+
.copy-btn:hover {
525+
background: rgba(63, 185, 80, 0.15);
526+
border-color: rgba(63, 185, 80, 0.3);
527+
color: #3fb950;
528+
}
529+
530+
.copy-btn.copied {
531+
background: rgba(63, 185, 80, 0.2);
532+
border-color: #3fb950;
533+
color: #3fb950;
534+
}
535+
503536
.line { display: block; }
504537
.gp { color: #3a5a3a; user-select: none; }
505538
.c { color: #4a6a4a; font-style: italic; }
@@ -773,9 +806,12 @@ <h2 class="section-title">Keyboard-first by design.</h2>
773806
<div class="section-label">/ install</div>
774807
<h2 class="section-title">Get started in seconds.</h2>
775808
<p class="section-desc">Available on every major platform. Choose your OS below.</p>
776-
<div class="code-block" style="margin-bottom: 20px;">
809+
<div class="code-block-wrap" style="margin-bottom: 20px;">
810+
<div class="code-block">
777811
<span class="line"><span class="c"># Quick install (Linux / macOS / WSL)</span></span>
778-
<span class="line"><span class="gp">$</span> <span class="cm">curl -fsSL https://raw.githubusercontent.com/Dark-Kernel/tuisic/master/install.sh <span class="hl">|</span> sh</span></span>
812+
<span class="line" id="quick-install-cmd"><span class="gp">$</span> <span class="cm">curl -fsSL https://raw.githubusercontent.com/Dark-Kernel/tuisic/master/install.sh <span class="hl">|</span> sh</span></span>
813+
</div>
814+
<button class="copy-btn" onclick="copyCmd()">copy</button>
779815
</div>
780816
<div class="install-tabs">
781817
<button class="install-tab active" data-tab="linux">Linux</button>
@@ -784,12 +820,16 @@ <h2 class="section-title">Get started in seconds.</h2>
784820
</div>
785821
<div id="panel-linux" class="install-panel active">
786822
<div class="code-block">
823+
<span class="line"><span class="c"># AppImage — portable, no deps needed</span></span>
824+
<span class="line"><span class="gp">$</span> <span class="cm">curl -fsSL https://github.com/Dark-Kernel/tuisic/releases/latest/download/tuisic-linux-x64.AppImage <span class="hl">-o</span> tuisic</span></span>
825+
<span class="line"><span class="gp">$</span> <span class="cm"><span class="hl">chmod +x</span> tuisic && ./tuisic</span></span>
826+
<span class="line"> </span><br>
787827
<span class="line"><span class="c"># AUR (Arch Linux) — recommended</span></span>
788828
<span class="line"><span class="gp">$</span> <span class="cm">yay -S tuisic-git</span></span>
789-
<span class="line"> </span>
790-
<span class="line"><span class="c"># Debian / Ubuntu</span></span>
829+
<span class="line"> </span><br>
830+
<span class="line"><span class="c"># Debian / Ubuntu — build deps</span></span>
791831
<span class="line"><span class="gp">$</span> <span class="cm">sudo apt-get install build-essential cmake pkg-config libfftw3-dev libmpv-dev libcurl4-openssl-dev libfmt-dev libsystemd-dev rapidjson-dev libpulse-dev</span></span>
792-
<span class="line"> </span>
832+
<span class="line"> </span><br>
793833
<span class="line"><span class="c"># Build from source</span></span>
794834
<span class="line"><span class="gp">$</span> <span class="cm">git clone https://github.com/Dark-Kernel/tuisic.git</span></span>
795835
<span class="line"><span class="gp">$</span> <span class="cm">cd tuisic</span></span>
@@ -888,6 +928,28 @@ <h3>AI-native integration</h3>
888928
document.getElementById('panel-' + tab.dataset.tab).classList.add('active');
889929
});
890930
});
931+
932+
function copyCmd() {
933+
const el = document.querySelector('#quick-install-cmd .cm');
934+
const text = el ? el.textContent : '';
935+
navigator.clipboard.writeText(text).then(() => {
936+
const btn = document.querySelector('.copy-btn');
937+
btn.textContent = 'copied';
938+
btn.classList.add('copied');
939+
setTimeout(() => {
940+
btn.textContent = 'copy';
941+
btn.classList.remove('copied');
942+
}, 2000);
943+
}).catch(() => {
944+
// fallback: select and execCommand
945+
const range = document.createRange();
946+
range.selectNodeContents(document.querySelector('#quick-install-cmd'));
947+
window.getSelection().removeAllRanges();
948+
window.getSelection().addRange(range);
949+
document.execCommand('copy');
950+
window.getSelection().removeAllRanges();
951+
});
952+
}
891953
</script>
892954

893955
</body>

0 commit comments

Comments
 (0)