iArt.ai
AI 모션 그래픽 소프트웨어, 누구나 사용할 수 있는 After Effects 대안, 텍스트 프롬프트로 몇 분 안에 애니메이션·설명 영상 제작
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
HUNGREE Goat is a self-hosted 24/7 internet radio and music streaming platform.
It was originally built for Lo-Fi Afrobeats and includes a public music player, a
browser-based operator control panel, YouTube livestream broadcasting, playlists, a music
library manager, looping/animated broadcast visuals, automatic health monitoring and
recovery, and a browser-based DJ/mixing studio.
You can run HUNGREE Goat on your own Linux computer or home server.
HUNGREE Goat is created and maintained by HUNGREE Goat Media.README 전문 보기 ↗HUNGREE Goat is a self-hosted 24/7 internet radio and music streaming platform.
It was originally built for Lo-Fi Afrobeats and includes a public music player, a browser-based operator control panel, YouTube livestream broadcasting, playlists, a music library manager, looping/animated broadcast visuals, automatic health monitoring and recovery, and a browser-based DJ/mixing studio.
You can run HUNGREE Goat on your own Linux computer or home server.
HUNGREE Goat is created and maintained by HUNGREE Goat Media.
A production incident (a YouTube broadcast silently stopped receiving data while every local indicator still looked green) drove a real reliability pass:
-progress heartbeat was still arriving — it could report healthy while the encoder
was live-locked (heartbeat ticking, frame/out_time frozen). The watchdog (StallDetector,
apps/control/hgc/streamer.py) now independently checks real forward progress, with
regression tests pinning down the exact failure mode.complete broadcast is terminal; this used to be a real UI bug).enableAutoStop=false for 24/7 streams. A temporary encoder stall used to be able to
turn into a permanently ended broadcast, because YouTube auto-completes a broadcast whose
enableAutoStop is on when ingest drops. New broadcasts default it off, with the
auto-start/monitor-stream tradeoffs documented in YouTube streaming.GET /v1/health/broadcast) — a real health signal (encoder
state, forward progress, YouTube ingest/lifecycle) instead of "the API process answered."At its core, HUNGREE Goat plays your own music library on a loop, 24/7, and can simultaneously:
It's built to run unattended: if the audio engine or the video stream crashes, it restarts itself automatically (see How it works).
Available:
apps/player) — a standalone site anyone can listen to, with mobile
playback behavior handled explicitly (not just "hope autoplay works")apps/control) — the operator's private cockpitliveStream/liveBroadcast
binding, and a backend-authoritative legal-transition state machine — the UI only ever
offers a lifecycle action the API would actually acceptenableAutoStop=false resilience for 24/7 broadcasts, so a temporary encoder hiccup
can't turn into a permanently-ended broadcastGET /v1/health/broadcast) — real encoder + YouTube state,
not just "the API process is up"/v1/*) for the website/player to usePlanned / not yet built:
Manage playback, schedules, playlists, music sources, broadcast outputs, metadata, health, alerts, and station controls from one browser-based dashboard.
Monitor the local streaming pipeline, stream quality, YouTube output, bitrate, realtime
performance, recovery status, warnings, and recent incidents. The screenshot above shows the
default, honest unverified status with no YouTube account connected: this app can always see
and control its own local encoder, but confirming YouTube itself is receiving the stream or
airing it live requires connecting a YouTube account (an optional, separate step) — see
YouTube streaming below. The exact status wording has since been
refined (real semantic states like VERIFIED LIVE/DEGRADED/YouTube Broadcast Ended
instead of one generic "not confirmed" message) — the screenshot's underlying behavior is
still accurate, only some copy has changed; a refresh is planned but not blocking.
Still needed: the public player, Broadcast Visuals, Workout DJ, and the new Monitoring & Alerts section. Add them here the same way — real screenshots, checked for anything account-specific before committing.
Minimum
Recommended
v4l2m2m on a Raspberry Pi)
— continuous 24/7 software encoding will otherwise keep a CPU core busy indefinitelyOptional
infra/gateway/)HGC_HW_BACKEND=softwareThere is not currently a single scripted installer (no working ./install.sh) — saying
otherwise would be documenting something that doesn't exist. What exists today is the exact
manual path below, built from the real Docker image, run scripts, and systemd units in
infra/beelink/ (the current production deployment method). It's accurate, but it is
several manual steps, not one command. See Installing HUNGREE Goat on a New
Computer for the full walkthrough; this is the
short version:
git clone [email protected]:amaeteventurestudios/hungreegoat.git
cd hungreegoat
docker build -f infra/beelink/Dockerfile -t hungree-goat/hgc:latest .
Then follow the full installation section below — you still need to lay out ~/hungree-goat/
on the host (app code + a secrets/ directory you create yourself + your music), point a
media mount at /srv/ai-node/storage/data, and install the systemd units before anything actually
runs.
This assumes a fresh Ubuntu/Debian Linux machine and walks through what it would actually take to rebuild HUNGREE Goat from GitHub plus a private backup of your own data (see Backups).
mesa-va-drivers on Ubuntu for Intel/AMD).git clone [email protected]:amaeteventurestudios/hungreegoat.git ~/hungree-goat-src
cd ~/hungree-goat-src
docker build -f infra/beelink/Dockerfile -t hungree-goat/hgc:latest .
~/hungree-goat/:
mkdir -p ~/hungree-goat/app ~/hungree-goat/secrets ~/hungree-goat/run ~/hungree-goat/logs ~/hungree-goat/data ~/hungree-goat/bin
cp -r apps/control/hgc apps/control/static ~/hungree-goat/app/
cp infra/beelink/bin/*.sh infra/pi/bin/*.sh ~/hungree-goat/bin/ && chmod +x ~/hungree-goat/bin/*.sh
chmod 700 ~/hungree-goat/secrets
/srv/ai-node/storage/data/ (see Music
library below for the expected layout) — from a backup, an external
drive, or by copying files in directly.apps/control/hgc/db.py, auth.py) — there is no
separate manual migration step today.cp infra/beelink/systemd/*.service ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now hungree-goat-control hungree-goat-liquidsoap@lofi hungree-goat-stream@lofi
loginctl enable-linger "$USER" # so these keep running after you log out
http://<this-machine>:8090 (or your reverse-proxied domain, see
infra/gateway/). Sign in with the operator account the app created on first start (see
apps/control/hgc/auth.py for exactly where that initial credential is written).The honest test for this section: if the current machine disappeared tomorrow, could you
buy another Linux box, follow the steps above, restore your private files and music from a
backup, and get HUNGREE Goat running again? Today, yes — but only by following these manual
steps carefully; there's no single button for it yet. See docs/RECOVERY.md for the
disaster-recovery-focused version of this same checklist.
Music lives outside Git, under a media mount at /srv/ai-node/storage/data/ (configurable via
the HGC_MEDIA environment variable — see apps/control/hgc/config.py):
/srv/ai-node/storage/data/
├── music/ per-station subfolders; this is what the library scanner walks
├── artwork/ cover art
├── animation/ looping background-visual source clips
├── fallback/ the emergency/silence-failover loop
├── jingles/
├── station-ids/
└── playlists/
Supported audio formats: mp3, m4a, aac, wav, flac, ogg, opus.
The library is discovered by scanning music/ — there's no separate "import" step; add
files to the right folder (or upload them through the Control dashboard's Library page) and
the scanner picks them up. Playlists are created and edited from the Control dashboard, not
by hand-editing files.
Music should not be committed to this repository — it's real audio content, not source code, and doesn't belong in Git history.
A YouTube stream key is a secret string YouTube Studio gives you (Go Live → Stream settings) that authorizes whatever you send to that URL to appear as your channel's live broadcast. Treat it like a password.
HUNGREE Goat stores it in ~/hungree-goat/secrets/youtube-<station>.env (mode 600, on the
server only) — set it from the Control dashboard's YouTube Setup → Stream URLs & Key panel,
never by hand-editing a file with a real key in it. Real stream keys must never be
committed to this repository (see infra/pi/youtube.env.example for what the file
actually looks like, with a placeholder).
Two modes, both fully supported:
YouTube's Live Streaming API enforces a real state machine — created → ready → testing → live → complete, with complete terminal (a completed broadcast can never be
transitioned back). HUNGREE Goat's backend is the sole authority on which transition is
legal right now (youtube_oauth.legal_transitions()); the dashboard only ever shows a button
for an action the backend has confirmed isn't already known-illegal — it used to be possible
to see Start Testing/Go Live enabled next to a complete broadcast, both of which the real
API correctly rejected. That's fixed.
Three contentDetails fields matter a lot for a 24/7 station, and are worth understanding
before you create or repair a broadcast by hand:
enableAutoStop — if true, YouTube will auto-end the broadcast after ingest drops
for a while. For a 24/7 station this is dangerous: a temporary encoder stall (see the
watchdog note below) can silently turn into a permanently completed broadcast. New
broadcasts HGC creates default this to false.enableAutoStart — if true, YouTube's own automatic mechanism owns the ready→live
transition, and cannot be changed after the broadcast is bound to a stream (the API
returns enableAutoStartModificationNotAllowed). HGC defaults this to false for
deterministic, HGC-driven control instead of waiting on an opaque auto-start timer.monitorStream.enableMonitorStream — if true, the legal path is
ready → testing → live; if false, ready → live directly is legal once ingest is
active/healthy. HGC defaults this to false for the same determinism reason above.To reconnect a stream that's stopped sending, use the "Reconnect to YouTube" action on the YouTube Setup page — it restarts the video/YouTube streaming process only (your music keeps playing; the audio engine is a separate process and isn't touched).
A real incident lesson worth internalizing: a healthy-looking FFmpeg process does not mean
media is actually progressing. FFmpeg can keep emitting a fresh -progress heartbeat on
schedule while its actual frame/out_time output has frozen — a live-lock, not a crash. The
watchdog (StallDetector in apps/control/hgc/streamer.py) checks three independent things,
not one: heartbeat recency, a first-heartbeat-never-arrived case, and — the one this incident
was missing — whether frame/out_time are actually advancing. See
apps/control/tests/test_streamer_stall.py for the regression coverage.
The recurring live-lock that watchdog kept catching every ~6h21m (22,865 s of FFmpeg runtime)
was traced on 2026-09-25 to the WAV header on Liquidsoap's loopback audio mount declaring a
fixed length, and fixed with -ignore_length 1 — full evidence in
docs/streaming/FFMPEG_STALL_INVESTIGATION.md,
operating steps in docs/streaming/RUNBOOK.md.
Full architecture in docs/monitoring-alerts.md — this is a summary.
Available:
GET /v1/health/broadcast?station=<sid> — the same real
health (healthy|degraded|critical|offline|unverified, encoder state, YouTube ingest/
lifecycle) the dashboard itself renders from, so a monitor's idea of "healthy" can never
drift from Control's.[TEST], never touch Liquidsoap/FFmpeg/the real YouTube
broadcast.Requires configuration:
~/hungree-goat/secrets/resend-api-key.txt; until then shown honestly as
Resend API key required. Sender [email protected], destination
[email protected]. The 5-minute-unresolved escalation tier is fully wired, not just
displayed.Provider configuration required (e.g. Twilio/Telnyx). Destination
(+1 840-999-2755) is already known; the provider is the only missing piece, and it's
optional — nothing else waits on it.Not a blocker:
docs/monitoring-alerts.md for exactly what's needed and the 4 checks to add manually in
the meantime. The Pi's own cron monitor works independently of this either way.HUNGREE Goat is four independent systemd --user units — restarting one never touches the
others:
systemctl --user restart hungree-goat-control # dashboard + API
systemctl --user restart hungree-goat-liquidsoap@lofi # this station's music engine
systemctl --user restart hungree-goat-stream@lofi # this station's video/YouTube output
systemctl --user restart hungree-goat-tunnel # reverse tunnel, only if you're using the gateway setup
(Replace lofi with your station id — this repo ships two, lofi and afrobeats.) You
can also start/stop/restart the video stream from the Control dashboard's Danger Zone,
without touching a terminal.
Deeper systemd/Docker details (resource limits, what each unit actually runs) live in
infra/beelink/README.md.
git pull the latest code into your clone of this repository.infra/beelink/Dockerfile or requirements.txt changed:
docker build -f infra/beelink/Dockerfile -t hungree-goat/hgc:latest .apps/control/hgc and apps/control/static into ~/hungree-goat/app/
(see infra/pi/deploy.sh for the exact rsync pattern this is based on — a Beelink-side
equivalent script doesn't exist yet; this is currently a manual copy).~/hungree-goat/secrets/, run/, logs/, data/
(your database), or the media mount — none of that comes from Git.hungree-goat-control to pick up backend (Python) changes — static
JS/CSS/HTML go live immediately since they're read from disk on each request; only
Python needs a restart.hungree-goat-liquidsoap@<station> or hungree-goat-stream@<station> if
you changed something in that specific process's own code (station.liq,
streamer.py) — both interrupt the live broadcast briefly, so don't restart them for an
unrelated change.Back up your database and secrets before any update you're unsure about (see below).
GitHub backs up the source code. It does not back up your private, running station. Before you'd ever need it, back these up separately and privately:
| What | Where it lives | Notes |
|---|---|---|
| Database | ~/hungree-goat/data/hungree-goat.sqlite3* | tracks, play history, settings, schedules |
| Secrets | ~/hungree-goat/secrets/ | stream keys, operator credentials, session key — never in Git |
| Music library | /srv/ai-node/storage/data/music/ | your actual audio files |
| Artwork | /srv/ai-node/storage/data/artwork/ | |
| Broadcast visuals | /srv/ai-node/storage/data/animation/ | |
| Playlists/metadata | /srv/ai-node/storage/data/playlists/ and the database above | |
| YouTube OAuth token | ~/hungree-goat/secrets/youtube-oauth-token.json | only if you've connected an account — see YouTube streaming |
| Monitoring config | ~/hungree-goat/secrets/ntfy-topic.txt, infra/monitoring/*.sh deployed on the two monitoring hosts | low-sensitivity but not public — see docs/security.md |
| Logs | ~/hungree-goat/logs/ | optional — useful for troubleshooting, not required for recovery |
See docs/RECOVERY.md for the full disaster-recovery checklist built around exactly this
list.
Real secrets must never be committed to this repository. Full stop.
What's local-only (already in .gitignore, verified — see the secret audit note in
docs/RECOVERY.md): secrets/, any *.env file, operator.json/operator-password.txt,
*.key/*.pem/*.crt/*.token, run/, logs/, data/, *.sqlite3*.
What's safe and tracked: example/template files with placeholder values only —
apps/control/secrets.example.md (documents what each secret file is, with no real values),
apps/player/.env.example, infra/pi/youtube.env.example. Copy these and fill in your own
values locally; never fill them in and commit the result.
Never expose, log, or commit: the YouTube stream key, cdn.ingestionInfo.streamName (the
same value as the stream key, under a different API field name), the OAuth client secret/JSON,
access/refresh tokens, SMTP or SMS provider credentials, the ntfy push topic, Uptime Kuma
credentials, session cookies, or any HGC authentication secret. Diagnostics and the Logs
export never include these. Filesystem permissions throughout ~/hungree-goat/secrets/ are
0700 (directory) / 0600 (files).
See docs/security.md for more.
In plain English, before the technical diagram:
Music Player (Liquidsoap) Keeps the station's music playing continuously — picks the next track, applies fades and volume normalization, and falls back to a backup source or emergency loop if something's wrong with the primary playlist.
Video Streamer (FFmpeg) Combines the music and the background visuals — plus a "Now Playing" overlay — into the outgoing video stream, encoded (in hardware, where available) and sent out over RTMPS.
Background Visuals Supplies the looping/rotating visual content shown behind the video stream, switching once per song.
Control
The browser dashboard (this repo's apps/control) used to manage the station — library,
playlists, schedule, YouTube setup, and live health monitoring.
Player
The public, listener-facing music player website (apps/player).
YouTube Output Sends the finished video stream to YouTube over RTMPS, with an optional OAuth connection for real ingest/lifecycle verification and lifecycle-safe controls. See YouTube streaming above.
Monitoring (see Monitoring & Alerts) A background watchdog inside Control persists telemetry and raises/resolves alerts on real encoder and YouTube state. Two independent monitors — external (Hetzner gateway) and local (Raspberry Pi, over the LAN) — check public reachability and semantic health from outside the broadcast pipeline entirely, so a monitoring failure can never affect the stream, and push outage/recovery notifications via ntfy.
Now the technical picture — component detail lives in docs/architecture.md:
hungreegoat.com ──┬── Listen Live ──▶ api.hungreegoat.com/v1/listen/lofi.mp3 ─┐
└── Watch YouTube ──▶ YouTube │
player.hungreegoat.com ── /v1/now-playing · up-next · schedule · stations ───┤ (public, read-only)
api.hungreegoat.com/v1/health/broadcast ── semantic health ───────────────────┤
▼
gateway (nginx, TLS) ── SSH reverse tunnel ── broadcast host
control.hungreegoat.com ── LOGIN ── same gateway ── /api/* (private) ──────────────────────┤ ├─ HUNGREE Goat Control (FastAPI :8090)
│ └─ watchdog: telemetry + alerts (sqlite)
├─ Liquidsoap 2.4.5 (Docker) ── AAC/MP3 mounts
└─ FFmpeg (hardware video) ── RTMPS ── YouTube (OAuth-verified)
hetzner-usg (gateway, external) ── cron ── checks public endpoints ──┐
pi-node-01 (LAN) ── cron ── checks Beelink directly over LAN ────────┴──▶ ntfy.sh push ──▶ your phone
| Path | What it is |
|---|---|
apps/website | The public HUNGREE Goat homepage (static, framework-free) |
apps/player | The public music player (AGPL-3.0 — see apps/player/NOTICE.md) |
apps/control | The operator dashboard and backend (FastAPI + a plain-JS SPA) — the bulk of the engineering lives here |
apps/dj-studio | Browser-based DJ/mixing studio (built on the MIT-licensed Aurdour project — see apps/dj-studio/NOTICE.md) |
infra/beelink | Current production deployment: Docker image, run scripts, systemd units |
infra/pi | The original Raspberry Pi bare-metal deployment — legacy, kept as a working rollback target |
infra/gateway | Public-facing nginx + SSH reverse-tunnel setup, so the private broadcast host is never directly exposed |
infra/monitoring | External (Hetzner) and local (Pi) monitoring scripts — see Monitoring & Alerts |
packages/brand | Shared brand assets — colors, fonts, logos |
packages/ui | Shared public-facing UI primitives (CSS) |
packages/shared | The public API client (hg-api.js) and the static-site build script |
docs/ | Architecture, deployment, development, DNS, security, and API reference docs |
systemctl --user status hungree-goat-liquidsoap@<station>,
then the Control dashboard's Pipeline Health (Music Player stage) and Logs page.systemctl --user status hungree-goat-control; if it's
not running, journalctl --user -u hungree-goat-control for why.0/unavailable usually means the
looping clip failed to decode (unsupported format/codec) and it's fallen back to the
default loop.logs/ffmpeg-<station>.log
(timestamped FFmpeg errors + stall snapshots) and logs/netprobe.log.~/hungree-goat/logs/ on the host, or the Control dashboard's
Logs page (Events / Audio engine / Video / Stream service / Control / Kernel).See docs/development.md for the full developer setup. In short:
apps/website, apps/player: npm run dev in that directory (see each package.json).apps/control: Python (FastAPI) backend under apps/control/hgc, plain-JS SPA under
apps/control/static (no build step — edit and reload). apps/control/requirements.txt
for backend dependencies; apps/control/tests for its test suite.apps/dj-studio: static, no-build ES modules — see its own package.json/NOTICE.md.This project doesn't yet have a formal contribution guide beyond that — if you're planning something larger than a small fix, opening an issue first to discuss it is a good idea.
HUNGREE Goat Community Edition is free and open source under the GNU Affero General
Public License v3.0 (AGPL-3.0) — see the root LICENSE file for the full text.
You can use, study, modify, and self-host the Community Edition under the terms of the
AGPL-3.0. If you modify the AGPL-covered software and make that modified version available
to users over a network, the AGPL's network-use clause (section 13) requires you to also make
your modified source available to those users — this applies to the original HUNGREE Goat
code covered by the root LICENSE; components under their own licenses (see License
below) follow their own terms instead.
This is a plain-English summary, not a substitute for reading the license itself or getting your own legal advice.
Need to use HUNGREE Goat in a proprietary product, a white-label deployment, a closed-source integration, or another commercial arrangement that doesn't fit the Community Edition's AGPL-3.0 terms?
Commercial licensing is available from HUNGREE Goat Media for the original HUNGREE Goat code,
where HUNGREE Goat Media holds the right to offer alternative terms. This does not relicense
or change the terms of any third-party component bundled in this repository — apps/player,
apps/dj-studio, the bundled fonts, and everything else listed in
THIRD_PARTY_NOTICES.md remain governed by their own licenses
regardless of any commercial license for HUNGREE Goat's original code.
Contact [email protected] to discuss commercial licensing. See the For Business page for the managed-hosting option as well.
HUNGREE Goat Community Edition — the original HUNGREE Goat code and documentation in this
repository (apps/website, apps/control, packages/brand excluding fonts, packages/ui,
packages/shared, infra/, and docs/) — is Copyright © 2023–2026 HUNGREE Goat Media
and licensed under the GNU Affero General Public License v3.0 (AGPL-3.0) — see the root
LICENSE file for the full text. Need different terms? See
Commercial Licensing above.
Several components are separately licensed and are not covered by the root LICENSE —
see THIRD_PARTY_NOTICES.md for the full breakdown:
apps/player is distributed under AGPL-3.0 in its own right (it's a derivative of a
third-party AGPL-3.0 project, copyright Gilles Momeni) — see apps/player/LICENSE and
apps/player/NOTICE.md for exactly what that requires (including that this repository's
player source stay published).apps/dj-studio's DJ engine is built on Aurdour (MIT) and its mastering DSP on
noisyloop/mastering (ISC) — see apps/dj-studio/NOTICE.md for the full, file-by-file
provenance breakdown, and THIRD_PARTY_NOTICES.md for the copyright holders.The root LICENSE's AGPL-3.0 grant applies only to the code and documentation original to
this repository — it does not and cannot override the separate licenses above.
If you're evaluating this repository for a public/open-source release, read docs/RECOVERY.md's
open-source-readiness notes first — the root LICENSE and the AGPL-3.0 apps/player
subtree currently make different promises, which needs a deliberate decision, not an
assumption, before going public.
apps/dj-studio