Compare commits
135 Commits
2decc5442d
...
codex/acti
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0030556525 | ||
|
|
905ce7bc0f | ||
|
|
19fe564e17 | ||
|
|
6248cb3c21 | ||
|
|
eff8577e37 | ||
|
|
1bd0c6f054 | ||
|
|
976e9bcc03 | ||
|
|
1dab8b9344 | ||
|
|
7667605e6b | ||
|
|
03e470a83a | ||
|
|
b922673192 | ||
|
|
ba37ee203e | ||
|
|
55035b4ee8 | ||
|
|
fffec89eaf | ||
|
|
0073339f8c | ||
|
|
e1a0f01fb9 | ||
|
|
66b91278b9 | ||
|
|
a70bf0f0f4 | ||
|
|
1a128d62f2 | ||
|
|
0fc40f339c | ||
|
|
86395a85a0 | ||
|
|
a9cf84077b | ||
|
|
f65d5af969 | ||
|
|
74e25ba41b | ||
|
|
4d768ae1fa | ||
|
|
cc5d04c0f5 | ||
|
|
f4343a6af4 | ||
|
|
f5c6851344 | ||
|
|
b873d57dca | ||
|
|
4fc8f309f8 | ||
|
|
582d05815d | ||
|
|
7ce85f9265 | ||
|
|
43a25654d0 | ||
|
|
421101d7fe | ||
|
|
43fd7c8917 | ||
|
|
a3c226320d | ||
|
|
0bdfd371ca | ||
|
|
a13f5a4259 | ||
|
|
5b0c60370f | ||
|
|
5ede162a72 | ||
|
|
6d8a15d249 | ||
|
|
3bf20b4c5a | ||
|
|
5c12288d68 | ||
|
|
4bfe3e4f9f | ||
|
|
a4560496be | ||
|
|
690abc8efe | ||
|
|
3c51a4176e | ||
|
|
dd5a8d0099 | ||
|
|
cf070880c8 | ||
|
|
24fed3cb7c | ||
|
|
9a3edd7b69 | ||
|
|
09a94d5b3b | ||
|
|
8f325722cf | ||
|
|
a5ea1739c4 | ||
|
|
95d75d2acd | ||
|
|
1eb403f44a | ||
|
|
b3bebb63f1 | ||
|
|
3703e6d599 | ||
|
|
1ffc609b50 | ||
|
|
e452f51957 | ||
|
|
0438f41630 | ||
|
|
10b0a80991 | ||
|
|
74e2736c08 | ||
|
|
7fb1989343 | ||
|
|
e1cf37ff29 | ||
|
|
20c7889a4e | ||
|
|
f1daaa2ef6 | ||
|
|
94c875b3d3 | ||
|
|
2d7054c2d2 | ||
|
|
8abbaf00d5 | ||
|
|
76464ed663 | ||
|
|
6ab3ded3da | ||
|
|
6f6bb17f0a | ||
|
|
15c0c296f4 | ||
|
|
f60574d6f8 | ||
|
|
00e5e20175 | ||
|
|
725f42932d | ||
|
|
d32117dab6 | ||
|
|
610c21b55e | ||
|
|
d9a62fa14e | ||
|
|
91096f29da | ||
|
|
c1965de873 | ||
|
|
b36ebeab59 | ||
|
|
3b57934ef2 | ||
|
|
9513420051 | ||
|
|
2255ec8259 | ||
|
|
d3fdf52602 | ||
|
|
fb977d5d08 | ||
|
|
3bbb519ed0 | ||
|
|
dce470baf4 | ||
|
|
d42108df4a | ||
|
|
5e94de0e59 | ||
|
|
385f612ab1 | ||
|
|
0c02125f13 | ||
|
|
81a6c1cd5b | ||
|
|
c659a7463b | ||
|
|
6ff1302d6d | ||
|
|
a952e792df | ||
|
|
551d7f46ce | ||
|
|
3bb1193a1e | ||
|
|
f05b57c656 | ||
|
|
b97168ada5 | ||
|
|
8102231d57 | ||
|
|
63d67b5e4d | ||
|
|
4aaca3e520 | ||
|
|
c27aa2ab12 | ||
|
|
83fb6ed112 | ||
|
|
48dadb2ea0 | ||
|
|
528783dc8e | ||
|
|
abc7e454f0 | ||
|
|
594d875477 | ||
|
|
3bb31a2e80 | ||
|
|
ffc3a1bfe3 | ||
|
|
fd087311a1 | ||
|
|
c2edee0131 | ||
|
|
24c1d3f017 | ||
|
|
e060cda578 | ||
|
|
068f6ae8b1 | ||
|
|
de124527b5 | ||
|
|
b13bf44311 | ||
|
|
13d4e552c0 | ||
|
|
2affe938b5 | ||
|
|
24843a768a | ||
|
|
f2ae69f4e3 | ||
|
|
15c5a3b43d | ||
|
|
fc60cfcab1 | ||
|
|
e5a3e9b5af | ||
|
|
63500f714d | ||
|
|
7802184b9c | ||
|
|
7272cd9aac | ||
|
|
1d9ace0337 | ||
|
|
275def9fb1 | ||
|
|
809d5271ef | ||
|
|
548692a028 | ||
|
|
b3533d0c01 |
11
.github/stargazer_countries.csv
vendored
@@ -33,6 +33,7 @@ AbeltjeNL,
|
||||
Acid-base,
|
||||
Actpohomoc,Ukraine
|
||||
Addonniss,
|
||||
Adouchee,France
|
||||
Adrian-Rosoga,United Kingdom
|
||||
Aersaud,United States
|
||||
Ag4m3mN0n,
|
||||
@@ -603,6 +604,7 @@ RicLund,Canada
|
||||
Richyread,
|
||||
RimmeVG,
|
||||
Rimpla,
|
||||
Rivlin77,
|
||||
Robbot,Ireland
|
||||
RobertZwets,
|
||||
RocketKuhr,
|
||||
@@ -650,6 +652,7 @@ Senpa,Italy
|
||||
SeriousM,Austria
|
||||
Seshpenguin,Canada
|
||||
Shadoweee77,
|
||||
SharkyRawr,Germany
|
||||
ShauneBoy,
|
||||
Shurik85,
|
||||
SieGoz,
|
||||
@@ -724,6 +727,7 @@ TheSpaceGod,
|
||||
Theboldhog,
|
||||
Theswedishgold,
|
||||
Thib1404,
|
||||
ThomasADavis,
|
||||
Thullalong69,Germany
|
||||
Tifeko,
|
||||
TiiMMY2CHAiiNZ,
|
||||
@@ -1153,7 +1157,7 @@ danctrl,Germany
|
||||
danez,United States
|
||||
danieldotnl,Netherlands
|
||||
dannybeeckman,
|
||||
dannybloomfield,
|
||||
dannybloomfield,United States
|
||||
danveitch76,
|
||||
darcouk,
|
||||
darianferrer,United Kingdom
|
||||
@@ -1394,6 +1398,7 @@ geniusboywonder,
|
||||
gentslava,
|
||||
geoffreylagaisse,Belgium
|
||||
georgek42,
|
||||
georgemitsionis,United Kingdom
|
||||
georgiasouthernbcilab,
|
||||
gerbal,United States
|
||||
gericho,
|
||||
@@ -1559,6 +1564,7 @@ jdungen,Netherlands
|
||||
jeff89179,United States
|
||||
jeffest-jeff,United States
|
||||
jeffreyphillips25907jeffreyphillips,
|
||||
jeffreyvangorkum,Netherlands
|
||||
jefmenegazzo,Brazil
|
||||
jeko89,
|
||||
jeroenmartens,
|
||||
@@ -1584,6 +1590,7 @@ joao-ribafeita,
|
||||
joaolpinho,Portugal
|
||||
jodfie,United States
|
||||
joe2k9b,
|
||||
joe8628,
|
||||
joealden,United Kingdom
|
||||
joeck,
|
||||
joetyson,United States
|
||||
@@ -1798,6 +1805,7 @@ marcschraepler,Austria
|
||||
marcusrbrown,
|
||||
mareklab,
|
||||
marevers,Germany
|
||||
marian-paun,Romania
|
||||
mariusvslprts,Germany
|
||||
markcshaz,
|
||||
markist,
|
||||
@@ -2160,6 +2168,7 @@ richmaster1343,
|
||||
rickwilliams08,
|
||||
rigerc,
|
||||
rikardronnkvist,Sweden
|
||||
rindlerblabla,
|
||||
rine77,
|
||||
ringzero24,
|
||||
rj10rd,
|
||||
|
||||
|
BIN
.github/stargazer_map.png
vendored
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 63 KiB |
BIN
.github/stats.png
vendored
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 1.7 KiB |
BIN
.github/stats_addons.png
vendored
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 5.0 KiB |
33
README.md
@@ -56,7 +56,7 @@ If you want to do add the repository manually, please follow the procedure highl
|
||||
|
||||
### Number of addons
|
||||
|
||||
- In the repository : 132
|
||||
- In the repository : 135
|
||||
- Installed : 508490
|
||||
|
||||
### Top 3
|
||||
@@ -176,6 +176,18 @@ If you want to do add the repository manually, please follow the procedure highl
|
||||
![smb][smb-badge]
|
||||
![localdisks][localdisks-badge]
|
||||
|
||||
✓  [Birdnet-go (custom version)](birdnet-go-dev/) : Realtime BirdNET soundscape analyzer, compiled from the alexbelgium/birdnet-go fork with all open PRs merged, with OpenVINO enabled for Intel CPU/iGPU acceleration (amd64-only test build)
|
||||
|
||||
  
|
||||

|
||||
![aarch64no][aarch64no-badge]
|
||||
![amd64][amd64-badge]
|
||||
![ingress][ingress-badge]
|
||||
![MariaDB][mariadb-badge]
|
||||
![mqtt][mqtt-badge]
|
||||
![smb][smb-badge]
|
||||
![localdisks][localdisks-badge]
|
||||
|
||||
✓ [Booksonic air](booksonic_air/) : platform for accessing the audiobooks you own wherever you are
|
||||
|
||||
  
|
||||
@@ -235,6 +247,14 @@ If you want to do add the repository manually, please follow the procedure highl
|
||||
![amd64][amd64-badge]
|
||||
![ingress][ingress-badge]
|
||||
|
||||
✓  [Claude Desktop](claude_desktop/) : Claude Desktop streamed through a browser with LinuxServer Selkies
|
||||
|
||||
  
|
||||

|
||||
![aarch64][aarch64-badge]
|
||||
![amd64][amd64-badge]
|
||||
![ingress][ingress-badge]
|
||||
|
||||
✓  [Cleanuparr](cleanuparr/) : Automatically removes stuck and unwanted downloads from your *arr and download clients
|
||||
|
||||
  
|
||||
@@ -428,7 +448,6 @@ If you want to do add the repository manually, please follow the procedure highl
|
||||

|
||||
![aarch64][aarch64-badge]
|
||||
![amd64][amd64-badge]
|
||||
![MariaDB][mariadb-badge]
|
||||
![smb][smb-badge]
|
||||
![localdisks][localdisks-badge]
|
||||
|
||||
@@ -438,7 +457,6 @@ If you want to do add the repository manually, please follow the procedure highl
|
||||

|
||||
![aarch64no][aarch64no-badge]
|
||||
![amd64][amd64-badge]
|
||||
![MariaDB][mariadb-badge]
|
||||
![smb][smb-badge]
|
||||
![localdisks][localdisks-badge]
|
||||
|
||||
@@ -455,7 +473,6 @@ If you want to do add the repository manually, please follow the procedure highl
|
||||

|
||||
![aarch64no][aarch64no-badge]
|
||||
![amd64][amd64-badge]
|
||||
![MariaDB][mariadb-badge]
|
||||
![smb][smb-badge]
|
||||
![localdisks][localdisks-badge]
|
||||
|
||||
@@ -472,7 +489,6 @@ If you want to do add the repository manually, please follow the procedure highl
|
||||

|
||||
![aarch64][aarch64-badge]
|
||||
![amd64][amd64-badge]
|
||||
![MariaDB][mariadb-badge]
|
||||
![smb][smb-badge]
|
||||
![localdisks][localdisks-badge]
|
||||
|
||||
@@ -901,6 +917,13 @@ If you want to do add the repository manually, please follow the procedure highl
|
||||
![smb][smb-badge]
|
||||
![localdisks][localdisks-badge]
|
||||
|
||||
✓  [Spotify to Plex](spotify_to_plex/) : Sync Spotify playlists to Plex
|
||||
|
||||
  
|
||||

|
||||
![aarch64][aarch64-badge]
|
||||
![amd64][amd64-badge]
|
||||
|
||||
✓  [Spotweb](spotweb/) : Spotweb is a decentralized usenet community based on the Spotnet protocol
|
||||
|
||||
  
|
||||
|
||||
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 1.2 KiB |
BIN
aurral/stats.png
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 1.4 KiB |
BIN
baikal/stats.png
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 1.6 KiB |
BIN
bazarr/stats.png
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 1.7 KiB |
495
birdnet-go-dev/CHANGELOG.md
Normal file
@@ -0,0 +1,495 @@
|
||||
## source-20260708-2 (08-07-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260708 (08-07-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260706-update (06-07-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260706 (06-07-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260705-3 (05-07-2026)
|
||||
- Harden the `output.sqlite.path` rewrite added for the persistence fix: reject paths containing `..` traversal segments (shared `validate_safe_path` check), and create the destination's parent directory under `/config` when the relative path includes a subdirectory (e.g. `db/birdnet.db`), since SQLite does not create missing parent directories itself.
|
||||
|
||||
## source-20260705-2 (05-07-2026)
|
||||
- Fix detections/database not persisting across restarts on a fresh install: upstream's default `config.yaml` ships `output.sqlite.path: birdnet.db` (relative) explicitly, so the missing-only (`//=`) seeding introduced previously never rewrote it to an absolute path. A relative path resolves against the app's ephemeral working directory, so the database was silently recreated empty on every restart. Any relative `output.sqlite.path` is now rewritten to live under the persistent `/config` on startup; values already set to an absolute path are left untouched. (https://github.com/tphakala/birdnet-go/discussions/3774)
|
||||
|
||||
## source-20260705 (05-07-2026)
|
||||
- Minor bugs fixed
|
||||
## source-2026070 (05-07-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260703 (03-07-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260702-em (02-07-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260702-2 (02-07-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260701 (01-07-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260629-3 (29-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260629-2 (29-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260629 (29-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260627-v3 (28-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260627-v2 (27-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260627 (27-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260626-5 (26-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260626-4 (26-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260626-3 (26-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260626 (26-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260625-14 (26-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260625-13 (25-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260625-12 (25-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260625-11 (25-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260625-10 (25-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260625-5 (25-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260625-4 (25-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260625-3 (25-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260625-2 (25-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260625 (25-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260624-6 (24-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260624-5 (24-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260624-4 (24-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260624-3 (24-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260624-2 (24-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260623-3 (23-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260623-2 (23-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260623 (23-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260622 (23-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260621-5 (22-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260621-4 (22-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260621-3 (22-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260621-2 (22-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260621-1 (21-06-2026)
|
||||
- Fix OpenVINO load failure: bundle oneTBB (libtbb.so.12) from OpenVINO 3rdparty libs so libopenvino_c.so resolves at runtime
|
||||
## source-20260620-13 (21-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260620-12 (21-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260620-11 (21-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260620-10 (21-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260620-7 (21-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260620-6 (21-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260620-5 (21-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260620-4 (21-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260620-3 (21-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260620-2 (21-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260620 (21-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260619-8 (20-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260619-7 (20-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260619-6 (20-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260619-5 (20-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260619-4 (20-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260619-3 (20-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260619-2 (20-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260619 (20-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260618-3 (18-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260618-2 (18-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260617-4 (18-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260617-3 (17-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260617-2 (17-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260617 (17-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260616-2 (16-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260616 (16-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260615bats (15-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260615 (15-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260614-2 (14-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260614 (14-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260613 (13-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260612-4 (13-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260612-3 (12-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260612-2 (12-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260612 (12-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260610-9 (11-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260610-8 (11-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260610-7 (11-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260610-6 (11-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260610-5 (11-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260610-4 (10-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260610-3 (10-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260610-2 (10-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260610 (10-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260608-8 (09-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260608-7 (09-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260608-6 (08-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260608-5 (08-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260608-4 (08-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260608-3 (08-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260608-2 (08-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260608 (08-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260607-4 (07-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260607-3 (07-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260607-2 (07-06-2026)
|
||||
- Minor bugs fixed
|
||||
## source-20260607 (07-06-2026)
|
||||
- **Test variant** of the birdnet-go add-on that compiles BirdNET-Go from the `alexbelgium/birdnet-go` fork instead of pulling the prebuilt `ghcr.io/tphakala/birdnet-go` image.
|
||||
- At build time, `merge-prs.sh` syncs the fork's `main` with the `tphakala/birdnet-go` upstream and merges every open non-draft ("in review") pull request on the fly, so the resulting binary is upstream main + all work currently under review.
|
||||
- Home Assistant integration layers (nginx ingress, modules, init scripts, options handling) are identical to the standard birdnet-go add-on.
|
||||
- Published as a separate image (`ghcr.io/alexbelgium/birdnet-go-source-{arch}`) so it never overwrites the production add-on image.
|
||||
- Fix (`01-structure.sh`): create the absolute `BIRDSONGS_FOLDER` target (e.g. the default `/config/clips`) before migrating clips from a legacy `/data/clips`, so upgrades with existing recordings no longer abort startup under `set -e`.
|
||||
|
||||
## nightly-20260601-2 (03-06-2026)
|
||||
- Minor bugs fixed
|
||||
## nightly-20260601 (2026-06-01)
|
||||
- Update to latest version from tphakala/birdnet-go (changelog : https://github.com/tphakala/birdnet-go/releases)
|
||||
## nightly-20260524 (2026-05-30)
|
||||
- Update to latest version from tphakala/birdnet-go (changelog : https://github.com/tphakala/birdnet-go/releases)
|
||||
## nightly-20260429-405 (2026-05-30)
|
||||
- Update to latest version from tphakala/birdnet-go (changelog : https://github.com/tphakala/birdnet-go/releases)
|
||||
## nightly-20260525-3 (28-05-2026)
|
||||
- New `mqtt_auto_config` addon option (default `false`). When `true` and the Home Assistant MQTT addon is active, `realtime.mqtt.{enabled,broker,username,password}` are written directly to `config.yaml` on every restart. When `false` but Mosquitto is detected, the addon still logs the broker details and reminds you about the option — nothing is written.
|
||||
- New `mariadb_auto_config` addon option (default `false`). When `true` and the Home Assistant MariaDB addon is active, `output.mysql.*` is filled in and `output.sqlite.enabled` is set to `false`. When `false` but MariaDB is detected, the addon logs the credentials and reminds you about the option.
|
||||
- **Breaking**: `output.sqlite.path` and `logging.file_output.*` are now seeded only when missing from `config.yaml` (previously overwritten every restart). Values changed through the BirdNET-Go UI or by hand-editing `config.yaml` now survive container restarts. If you relied on `LOG_MAX_SIZE_MB` / `LOG_MAX_AGE_DAYS` addon options to override an existing setting in `config.yaml`, remove the existing key from `config.yaml` or edit it directly — the option will only be applied on first run.
|
||||
- **Breaking (UI only)**: The nginx ingress reverse-proxy no longer rewrites HTML `href`/`src`/`action` attributes; upstream BirdNET-Go handles those itself via `X-Ingress-Path`. JavaScript string-literal rewrites are unchanged. Please file an issue if you see broken images, links, or forms in the ingress UI after upgrade.
|
||||
- Fix database-migration restore: the timestamped backup created during a `BIRDSONGS_FOLDER` change was being written to the script's working directory and looked up under a fresh timestamp on restore, so a SQL failure left the user unable to recover. Backup path is now absolute and reused for restore.
|
||||
- Harden the `BIRDSONGS_FOLDER` SQL/YAML path substitution: paths containing characters outside `[A-Za-z0-9._/-]` are now rejected up front instead of being interpolated raw into the SQL UPDATE statement.
|
||||
- Tolerate a missing internet connection on first boot: if the default `config.yaml` cannot be downloaded from GitHub, the init script now seeds an empty YAML document so the addon-defaults block populates a usable config (rather than aborting the script on the next `yq` call under `set -e`).
|
||||
- Warn (without failing the build) if the upstream `entrypoint.sh` patch target drifts in a new nightly.
|
||||
- Remove a dead nginx upstream definition that pointed at an unused port.
|
||||
|
||||
## nightly-20260525-2 (26-05-2026)
|
||||
- Suppress noisy startup logs: silence `chmod /dev/snd` errors on the read-only HA mount, and hide unavailable ALSA plugins (JACK, OSS, dsnoop) from device enumeration so libjack and pcm_oss/dsnoop probes no longer print at launch. ALSA overrides are written to `/root/.asoundrc` (since `/etc/asound.conf` is read-only in this environment).
|
||||
- Allow advanced users to override the ALSA config by dropping a custom `asound.conf` into the addon config folder.
|
||||
- Add LOG_MAX_SIZE_MB and LOG_MAX_AGE_DAYS addon options to manage log storage size
|
||||
- Automatically trim log files exceeding configured age on startup
|
||||
|
||||
## nightly-20260525 (26-05-2026)
|
||||
- Minor bugs fixed
|
||||
|
||||
## nightly-20260511-414-2 (22-05-2026)
|
||||
- Minor bugs fixed
|
||||
|
||||
## nightly-20260511-414 (2026-05-16)
|
||||
- Update to latest version from tphakala/birdnet-go (changelog : https://github.com/tphakala/birdnet-go/releases)
|
||||
|
||||
## nightly-20260429-405 (2026-05-02)
|
||||
- Update to latest version from tphakala/birdnet-go (changelog : https://github.com/tphakala/birdnet-go/releases)
|
||||
|
||||
## nightly-20260321-397 (2026-03-26)
|
||||
- Update to latest version from tphakala/birdnet-go (changelog : https://github.com/tphakala/birdnet-go/releases)
|
||||
|
||||
## nightly-20260315 (2026-03-21)
|
||||
- Update to latest version from tphakala/birdnet-go (changelog : https://github.com/tphakala/birdnet-go/releases)
|
||||
|
||||
## nightly-20260311 (2026-03-14)
|
||||
- Update to latest version from tphakala/birdnet-go (changelog : https://github.com/tphakala/birdnet-go/releases)
|
||||
## nightly-20260118-2 (17-02-2026)
|
||||
- Minor bugs fixed
|
||||
|
||||
## nightly-20260118 (2026-01-21)
|
||||
- Update to latest version from tphakala/birdnet-go (changelog : https://github.com/tphakala/birdnet-go/releases)
|
||||
|
||||
## nightly-20260113 (2026-01-14)
|
||||
- Update to latest version from tphakala/birdnet-go (changelog : https://github.com/tphakala/birdnet-go/releases)
|
||||
|
||||
## nightly-20260111 (2026-01-12)
|
||||
- Update to latest version from tphakala/birdnet-go (changelog : https://github.com/tphakala/birdnet-go/releases)
|
||||
|
||||
## nightly-20260110 (2026-01-10)
|
||||
- Update to latest version from tphakala/birdnet-go (changelog : https://github.com/tphakala/birdnet-go/releases)
|
||||
## nightly-20251223-2 (2025-12-27)
|
||||
- Minor bugs fixed
|
||||
## nightly-20251224 (2025-12-24)
|
||||
- Minor bugs fixed
|
||||
|
||||
## nightly-20251223 (2025-12-23)
|
||||
- Update to latest version from tphakala/birdnet-go (changelog : https://github.com/tphakala/birdnet-go/releases)
|
||||
|
||||
## nightly-20251214 (2025-12-20)
|
||||
- Update to latest version from tphakala/birdnet-go (changelog : https://github.com/tphakala/birdnet-go/releases)
|
||||
- Added support for configuring extra environment variables via the `env_vars` add-on option alongside config.yaml. See https://github.com/alexbelgium/hassio-addons/wiki/Add-Environment-variables-to-your-Addon-2 for details.
|
||||
|
||||
- Preserve the microphone selected in the BirdNET-Go UI unless the `homeassistant_microphone` option explicitly forces the default device.
|
||||
|
||||
## "nightly-20251028" (2025-11-01)
|
||||
- Minor bugs fixed
|
||||
|
||||
## nightly-20251028 (2025-11-01)
|
||||
- Update to latest version from tphakala/birdnet-go (changelog : https://github.com/tphakala/birdnet-go/releases)
|
||||
## "nightly-20251012" (2025-10-18)
|
||||
- Minor bugs fixed
|
||||
|
||||
## nightly-20251012 (2025-10-18)
|
||||
- Update to latest version from tphakala/birdnet-go (changelog : https://github.com/tphakala/birdnet-go/releases)
|
||||
|
||||
## nightly-20251008 (2025-10-11)
|
||||
- Update to latest version from tphakala/birdnet-go (changelog : https://github.com/tphakala/birdnet-go/releases)
|
||||
## nightly-20250904_6 (2025-09-17)
|
||||
- New option "homeassistant_microphone". If set to true, will use homeassistant's microphone by setting the audio_card to "default". Please use the addon options to select the device to which "default" is allocated
|
||||
|
||||
## nightly-20250904 (2025-09-06)
|
||||
- Update to latest version from tphakala/birdnet-go (changelog : https://github.com/tphakala/birdnet-go/releases)
|
||||
|
||||
## nightly-20250826 (2025-08-30)
|
||||
- Update to latest version from tphakala/birdnet-go (changelog : https://github.com/tphakala/birdnet-go/releases)
|
||||
|
||||
## nightly-20250813 (2025-08-16)
|
||||
- Update to latest version from tphakala/birdnet-go (changelog : https://github.com/tphakala/birdnet-go/releases)
|
||||
|
||||
## nightly-20250805 (2025-08-09)
|
||||
- Update to latest version from tphakala/birdnet-go (changelog : https://github.com/tphakala/birdnet-go/releases)
|
||||
## nightly-20250731-4 (2025-08-04)
|
||||
- Minor bugs fixed
|
||||
## nightly-20250731-3 (2025-08-04)
|
||||
- Minor bugs fixed
|
||||
## nightly-20250731-2 (2025-08-02)
|
||||
- Minor bugs fixed
|
||||
|
||||
## nightly-20250731 (2025-08-01)
|
||||
- Update to latest version from tphakala/birdnet-go (changelog : https://github.com/tphakala/birdnet-go/releases)
|
||||
## nightly-20250730 (2025-07-30)
|
||||
- Minor bugs fixed
|
||||
## nightly-20250725-2 (2025-07-28)
|
||||
- Fix /asset path
|
||||
- Added 9090 telemetry port
|
||||
|
||||
## nightly-20250725 (2025-07-25)
|
||||
- Update to latest version from tphakala/birdnet-go (changelog : https://github.com/tphakala/birdnet-go/releases)
|
||||
|
||||
## nightly-20250710 (2025-07-12)
|
||||
|
||||
- Update to latest version from tphakala/birdnet-go (changelog : https://github.com/tphakala/birdnet-go/releases)
|
||||
|
||||
## 20250710 (2025-07-12)
|
||||
|
||||
- Update to latest version from tphakala/birdnet-go (changelog : https://github.com/tphakala/birdnet-go/releases)
|
||||
|
||||
## 20250704 (2025-07-07)
|
||||
|
||||
- Minor bugs fixed
|
||||
|
||||
## 20250508 (2025-07-05)
|
||||
|
||||
- Update to latest version from tphakala/birdnet-go (changelog : https://github.com/tphakala/birdnet-go/releases)
|
||||
|
||||
## 20250419 (2025-05-17)
|
||||
|
||||
- Update to latest version from tphakala/birdnet-go (changelog : https://github.com/tphakala/birdnet-go/releases)
|
||||
|
||||
## 20250427-7 (2025-05-15)
|
||||
|
||||
- Breaking change: COMMAND addon option removed. Please instead use the config.yaml to define the RTSP feeds
|
||||
- Use entrypoint
|
||||
|
||||
## 20250427-2 (2025-04-27)
|
||||
|
||||
- Minor bugs fixed
|
||||
|
||||
## 20250427 (2025-04-27)
|
||||
|
||||
- Minor bugs fixed
|
||||
|
||||
## 20250316 (2025-04-26)
|
||||
|
||||
- Update to latest version from tphakala/birdnet-go (changelog : https://github.com/tphakala/birdnet-go/releases)
|
||||
|
||||
## 0.6.4-3 (2025-04-07)
|
||||
|
||||
- Minor bugs fixed
|
||||
|
||||
## 0.6.4-2 (2025-03-30)
|
||||
|
||||
- Minor bugs fixed
|
||||
|
||||
## 0.6.4 (2025-03-17)
|
||||
|
||||
- Minor bugs fixed
|
||||
|
||||
## 0.6.3 (2025-03-15)
|
||||
|
||||
- Update to latest version from tphakala/birdnet-go (changelog : https://github.com/tphakala/birdnet-go/releases)
|
||||
|
||||
## 0.6.2-2 (2025-02-21)
|
||||
|
||||
- Minor bugs fixed
|
||||
|
||||
## 0.6.2 (2025-02-21)
|
||||
|
||||
- Update to latest version from tphakala/birdnet-go (changelog : https://github.com/tphakala/birdnet-go/releases)
|
||||
|
||||
## 20250126-2 (2025-02-21)
|
||||
|
||||
- Minor bugs fixed
|
||||
|
||||
## 20250126 (2025-02-15)
|
||||
|
||||
- Update to latest version from tphakala/birdnet-go (changelog : https://github.com/tphakala/birdnet-go/releases)
|
||||
|
||||
## 0.6.0-nightly-20250124 (2025-01-25)
|
||||
|
||||
- Minor bugs fixed
|
||||
|
||||
## 0.6.0-4 (2025-01-21)
|
||||
|
||||
- Fix sounds play
|
||||
- Correct sqlite for //
|
||||
|
||||
## 0.6.0 (2025-01-18)
|
||||
|
||||
- Update to latest version from tphakala/birdnet-go (changelog : https://github.com/tphakala/birdnet-go/releases)
|
||||
|
||||
## 20250103-10 (2025-01-17)
|
||||
|
||||
- BREAKING CHANGE : improve implementation of addon options such as Birdsongs folder. Please check the log at first start if anything is different than you expected
|
||||
- WARNING : your files will move to the new Birdsongs folder in case of change
|
||||
- WARNING : your db will be modified in case of Birdsongs folder change to still allow access to files. A backup will always be created
|
||||
- Fix ingress issues
|
||||
|
||||
## 20250103 (2025-01-11)
|
||||
|
||||
- Update to latest version from tphakala/birdnet-go (changelog : https://github.com/tphakala/birdnet-go/releases)
|
||||
|
||||
## 25-4 (2024-12-29)
|
||||
|
||||
- Fixed https://github.com/alexbelgium/hassio-addons/issues/1687
|
||||
|
||||
## 25-3 (2024-12-28)
|
||||
|
||||
- avx2 support added by @tphakala
|
||||
|
||||
## 25-2 (2024-12-21)
|
||||
|
||||
- Minor bugs fixed
|
||||
|
||||
## 25 (2024-12-21)
|
||||
|
||||
- Update to latest version from tphakala/birdnet-go (changelog : https://github.com/tphakala/birdnet-go/releases)
|
||||
|
||||
## 0.5.5-11 (2024-10-22)
|
||||
|
||||
- Minor bugs fixed
|
||||
|
||||
## 0.5.5-10 (2024-09-30)
|
||||
|
||||
- Minor bugs fixed
|
||||
|
||||
## 0.5.5-9 (2024-07-06)
|
||||
|
||||
- Correct indentation issue
|
||||
|
||||
## 0.5.5-8 (2024-07-03)
|
||||
|
||||
- New option : set the audio clip directory from addon options
|
||||
|
||||
## 0.5.5-2 (2024-06-25)
|
||||
|
||||
- Minor bugs fixed
|
||||
|
||||
## 0.5.5 (2024-06-22)
|
||||
|
||||
- Update to latest version from tphakala/birdnet-go (changelog : https://github.com/tphakala/birdnet-go/releases)
|
||||
|
||||
## 0.5.5 (2024-06-20)
|
||||
|
||||
- Minor bugs fixed
|
||||
|
||||
## 0.5.3-3 (2024-06-07)
|
||||
|
||||
- Minor bugs fixed
|
||||
|
||||
## 0.5.3-2 (2024-06-07)
|
||||
|
||||
- Minor bugs fixed
|
||||
|
||||
## 0.5.3 (2024-05-26)
|
||||
|
||||
- Minor bugs fixed
|
||||
|
||||
## 0.5.2 (2024-05-04)
|
||||
|
||||
- Minor bugs fixed
|
||||
|
||||
## 0.5.1-4 (2024-04-23)
|
||||
|
||||
- Feat : provide mariadb information in the startup log to allow its usage
|
||||
|
||||
## 0.5.1-3 (2024-04-23)
|
||||
|
||||
- Feat : Allow mounting of SMB and local drives to store the audio clips on an external drive
|
||||
|
||||
## 0.5.1 (2024-04-22)
|
||||
|
||||
- Initial build
|
||||
365
birdnet-go-dev/Dockerfile
Normal file
@@ -0,0 +1,365 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
#============================#
|
||||
# ALEXBELGIUM'S DOCKERFILE #
|
||||
# BirdNET-Go (OpenVINO/AMD64)#
|
||||
#============================#
|
||||
# _.------.
|
||||
# _.-` ('>.-`"""-.
|
||||
# '.--'` _'` _ .--.)
|
||||
# -' '-.-';` `
|
||||
# ' - _.' ``'--.
|
||||
# '---` .-'""``
|
||||
# /`
|
||||
#=== Home Assistant Addon ===#
|
||||
#
|
||||
# AMD64-only, OpenVINO-enabled build of the BirdNET-Go add-on.
|
||||
# The binary is compiled from the alexbelgium/birdnet-go fork with the
|
||||
# OpenVINO inference backend enabled (openvino build tag). The OpenVINO
|
||||
# 2026.2 runtime libraries are bundled in the image, enabling:
|
||||
# - Faster CPU inference on modern Intel CPUs (AVX-512/AMX)
|
||||
# - Intel iGPU inference when /dev/dri is passed from the host
|
||||
#
|
||||
# Before compiling, "merge-prs.sh" clones the fork, fast-forwards its main
|
||||
# onto the tphakala/birdnet-go upstream and merges every OPEN, NON-DRAFT
|
||||
# pull request on the fly. Home Assistant integration layers (2-6) are then
|
||||
# applied on top and are byte-for-byte identical to the upstream variant.
|
||||
#
|
||||
# Build stages 0-1 mirror tphakala/birdnet-go's Docker/Dockerfile; if
|
||||
# upstream changes its build (Go/Node/onnxruntime versions, task names)
|
||||
# sync them here.
|
||||
|
||||
##########################################################
|
||||
# 0 Prepare merged BirdNET-Go source tree (fork + PRs) #
|
||||
##########################################################
|
||||
|
||||
FROM alpine/git:latest AS birdnet-source
|
||||
ARG BIRDNET_FORK=alexbelgium/birdnet-go
|
||||
ARG BIRDNET_UPSTREAM=tphakala/birdnet-go
|
||||
# BUILD_DATE changes on every CI run, busting this layer's cache so the fork is
|
||||
# re-cloned and the open PRs are re-merged "on the fly" on every build.
|
||||
ARG BUILD_DATE=unknown
|
||||
RUN apk add --no-cache bash curl jq
|
||||
COPY merge-prs.sh /usr/local/bin/merge-prs.sh
|
||||
RUN chmod +x /usr/local/bin/merge-prs.sh && \
|
||||
echo "Build date marker: ${BUILD_DATE}" && \
|
||||
BIRDNET_FORK="${BIRDNET_FORK}" BIRDNET_UPSTREAM="${BIRDNET_UPSTREAM}" \
|
||||
/usr/local/bin/merge-prs.sh /birdnet-src
|
||||
|
||||
##########################################################
|
||||
# 0b Download OpenVINO runtime libraries for amd64 #
|
||||
##########################################################
|
||||
|
||||
FROM alpine:3 AS openvino-libs
|
||||
ARG OPENVINO_BUILD=2026.2.0.21903.52ddc073857
|
||||
ARG OPENVINO_RELEASE=2026.2
|
||||
|
||||
# Download the x86_64 OpenVINO runtime package and extract runtime/lib/intel64.
|
||||
# The same build id is used for the C API headers downloaded during compilation
|
||||
# (see Taskfile.yml OPENVINO_BUILD), ensuring header/runtime version parity.
|
||||
# We use the arm64 package for headers (arch-independent C declarations) but the
|
||||
# x86_64 package here for the actual runtime .so files.
|
||||
#
|
||||
# OpenVINO links against its own bundled oneTBB (libtbb.so.12, libtbbmalloc*),
|
||||
# which does NOT live in runtime/lib/intel64 but in runtime/3rdparty/tbb/lib.
|
||||
# It must be bundled too, otherwise dlopen("libopenvino_c.so") fails at runtime
|
||||
# with "libtbb.so.12: cannot open shared object file: No such file or directory"
|
||||
# and the OpenVINO backend silently falls back / GPU planning treats the device
|
||||
# as unavailable.
|
||||
RUN apk add --no-cache curl && \
|
||||
mkdir -p /openvino && \
|
||||
curl -fsSL \
|
||||
"https://storage.openvinotoolkit.org/repositories/openvino/packages/${OPENVINO_RELEASE}/linux/openvino_toolkit_ubuntu22_${OPENVINO_BUILD}_x86_64.tgz" \
|
||||
-o /tmp/openvino.tgz && \
|
||||
tar -xzf /tmp/openvino.tgz -C /tmp/ --strip-components=1 && \
|
||||
cd /tmp/runtime/lib/intel64 && \
|
||||
tar -cf - . | tar -xf - -C /openvino/ && \
|
||||
# Bundle OpenVINO's own oneTBB runtime (preserving symlinks with cp -a).
|
||||
# Search the whole 3rdparty tree so the copy survives minor layout changes
|
||||
# between OpenVINO releases. Fail the build loudly if libtbb is missing,
|
||||
# since the runtime is unusable without it.
|
||||
find /tmp/runtime/3rdparty -name 'libtbb*.so*' -exec cp -a {} /openvino/ \; && \
|
||||
if ! ls /openvino/libtbb.so.12* >/dev/null 2>&1; then \
|
||||
echo "ERROR: libtbb.so.12 not found in OpenVINO package 3rdparty/tbb" >&2; \
|
||||
exit 1; \
|
||||
fi && \
|
||||
rm -rf /tmp/openvino.tgz /tmp/runtime /tmp/tools /tmp/python \
|
||||
/tmp/samples /tmp/install_dependencies 2>/dev/null || true
|
||||
|
||||
#########################################################################
|
||||
# 1a Build environment (mirrors tphakala/birdnet-go Docker/Dockerfile) #
|
||||
#########################################################################
|
||||
|
||||
FROM --platform=$BUILDPLATFORM golang:1.26-trixie AS buildenv
|
||||
ARG BUILD_VERSION
|
||||
ENV BUILD_VERSION=${BUILD_VERSION:-unknown}
|
||||
|
||||
# Install Task and other dependencies
|
||||
RUN apt-get update -q && apt-get install -q -y \
|
||||
curl \
|
||||
git \
|
||||
sudo \
|
||||
zip \
|
||||
gcc-aarch64-linux-gnu && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install Node.js v24 from NodeSource
|
||||
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
||||
RUN curl -fsSL https://deb.nodesource.com/setup_24.x | bash - && \
|
||||
apt-get install -y nodejs && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install Task
|
||||
RUN sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b /usr/local/bin
|
||||
|
||||
# Create dev-user for building
|
||||
RUN groupadd --gid 10001 dev-user && \
|
||||
useradd --uid 10001 --gid dev-user --shell /bin/bash --create-home dev-user && \
|
||||
usermod -aG sudo dev-user && \
|
||||
usermod -aG audio dev-user && \
|
||||
echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers && \
|
||||
mkdir -p /home/dev-user/src && \
|
||||
mkdir -p /home/dev-user/lib && \
|
||||
mkdir -p /home/dev-user/.cache && \
|
||||
mkdir -p /home/dev-user/.npm && \
|
||||
chown -R dev-user:dev-user /home/dev-user
|
||||
|
||||
USER dev-user
|
||||
WORKDIR /home/dev-user/src/BirdNET-Go
|
||||
|
||||
# Bring in the merged source tree (fork main + upstream sync + open PRs)
|
||||
COPY --from=birdnet-source --chown=dev-user /birdnet-src ./
|
||||
|
||||
# Pre-build frontend once in the shared buildenv stage
|
||||
ENV PUPPETEER_SKIP_DOWNLOAD=true
|
||||
RUN task frontend-build
|
||||
|
||||
##################
|
||||
# 1b Build stage #
|
||||
##################
|
||||
|
||||
FROM --platform=$BUILDPLATFORM buildenv AS build
|
||||
ARG BUILD_VERSION
|
||||
ENV BUILD_VERSION=${BUILD_VERSION:-unknown}
|
||||
ARG ONNXRUNTIME_VERSION=1.25.1
|
||||
|
||||
# Download ONNX Runtime for amd64 (x64)
|
||||
RUN echo "Downloading ONNX Runtime ${ONNXRUNTIME_VERSION} for x64" && \
|
||||
curl -fsSL "https://github.com/microsoft/onnxruntime/releases/download/v${ONNXRUNTIME_VERSION}/onnxruntime-linux-x64-${ONNXRUNTIME_VERSION}.tgz" \
|
||||
-o /tmp/onnxruntime.tgz && \
|
||||
mkdir -p /tmp/onnxruntime && \
|
||||
tar -xzf /tmp/onnxruntime.tgz -C /tmp/onnxruntime --strip-components=1 && \
|
||||
cp /tmp/onnxruntime/lib/libonnxruntime*.so* /home/dev-user/lib/ && \
|
||||
rm -rf /tmp/onnxruntime /tmp/onnxruntime.tgz
|
||||
|
||||
# Build BirdNET-Go for amd64 with OpenVINO enabled.
|
||||
# OPENVINO=true compiles in the openvino build tag, enabling the OpenVINO
|
||||
# inference backend (dlopen'd at runtime; falls back to ONNX Runtime when
|
||||
# libopenvino_c.so is absent). The noembed_linux_amd64 task defaults to
|
||||
# OPENVINO=true anyway; we make it explicit here for clarity.
|
||||
RUN --mount=type=cache,target=/go/pkg/mod,uid=10001,gid=10001 \
|
||||
--mount=type=cache,target=/home/dev-user/.cache/go-build,uid=10001,gid=10001 \
|
||||
task check-tensorflow && \
|
||||
echo "Building amd64 with OpenVINO enabled, BUILD_VERSION=${BUILD_VERSION}" && \
|
||||
BUILD_VERSION="${BUILD_VERSION}" DOCKER_LIB_DIR=/home/dev-user/lib task noembed_linux_amd64 OPENVINO=true
|
||||
|
||||
#####################################################
|
||||
# 1c BirdNET-Go runtime base (mirrors upstream) #
|
||||
#####################################################
|
||||
|
||||
FROM debian:trixie-slim AS birdnet-runtime
|
||||
|
||||
# Copy TFLite model files (amd64 uses TFLite; OpenVINO reads them via its
|
||||
# TFLite frontend plugin bundled in the OpenVINO runtime below)
|
||||
RUN mkdir -p /models
|
||||
COPY --from=build /home/dev-user/src/BirdNET-Go/internal/classifier/data/*.tflite /models/
|
||||
RUN chmod -R a+r /models/*.tflite 2>/dev/null || true && \
|
||||
chmod a+x /models
|
||||
|
||||
# Install ALSA library, SOX for audio processing, and system utilities.
|
||||
# ocl-icd-libopencl1 provides the OpenCL ICD loader; combined with
|
||||
# /dev/dri passthrough from the host it enables Intel iGPU inference.
|
||||
RUN apt-get update -q && apt-get install -q -y --no-install-recommends \
|
||||
adduser \
|
||||
ca-certificates \
|
||||
libasound2 \
|
||||
ffmpeg \
|
||||
sox \
|
||||
libsox-fmt-mp3 \
|
||||
procps \
|
||||
iproute2 \
|
||||
net-tools \
|
||||
curl \
|
||||
wget \
|
||||
nano \
|
||||
vim \
|
||||
less \
|
||||
tzdata \
|
||||
tzdata-legacy \
|
||||
jq \
|
||||
strace \
|
||||
lsof \
|
||||
bash-completion \
|
||||
gosu \
|
||||
ocl-icd-libopencl1 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Copy TensorFlow Lite library from build stage
|
||||
COPY --from=build /home/dev-user/lib/libtensorflowlite_c.so* /usr/lib/
|
||||
|
||||
# Copy ONNX Runtime libraries from build stage
|
||||
COPY --from=build /home/dev-user/lib/libonnxruntime*.so* /usr/lib/
|
||||
|
||||
# Copy OpenVINO runtime libraries (libopenvino_c.so, CPU/GPU plugins,
|
||||
# TFLite frontend, plugins.xml, bundled oneTBB libtbb.so.12, etc.) into a
|
||||
# dedicated directory and register it with ldconfig so both
|
||||
# dlopen("libopenvino_c.so") and its libtbb.so.12 dependency resolve.
|
||||
# plugins.xml is co-located with libopenvino.so so device plugin
|
||||
# discovery works without additional environment variables.
|
||||
COPY --from=openvino-libs /openvino/ /usr/lib/openvino/
|
||||
RUN echo "/usr/lib/openvino" > /etc/ld.so.conf.d/openvino.conf && ldconfig
|
||||
|
||||
# Include reset_auth tool from build stage
|
||||
COPY --from=build /home/dev-user/src/BirdNET-Go/reset_auth.sh /usr/bin/
|
||||
RUN chmod +x /usr/bin/reset_auth.sh
|
||||
|
||||
# Add entrypoint and startup wrapper scripts from build stage
|
||||
COPY --from=build /home/dev-user/src/BirdNET-Go/Docker/entrypoint.sh /usr/bin/
|
||||
RUN chmod +x /usr/bin/entrypoint.sh
|
||||
COPY --from=build /home/dev-user/src/BirdNET-Go/Docker/startup-wrapper.sh /usr/bin/
|
||||
RUN chmod +x /usr/bin/startup-wrapper.sh
|
||||
|
||||
# Create config and data directories with proper permissions for rootless compatibility
|
||||
RUN mkdir -p /config /data/clips /data/models && \
|
||||
chmod 777 /config /data /data/clips /data/models
|
||||
|
||||
# Install the freshly built BirdNET-Go binary
|
||||
COPY --from=build /home/dev-user/src/BirdNET-Go/bin /usr/bin/
|
||||
|
||||
# Enable openvino
|
||||
ARG NEO_VERSION=26.22.38646.4
|
||||
ARG IGC_VERSION=2.36.3+21719
|
||||
RUN groupadd -g 109 render || true && \
|
||||
usermod -aG render root && \
|
||||
\
|
||||
apt-get update -q && apt-get install -q -y --no-install-recommends wget ocl-icd-libopencl1 libdrm2 libdrm-intel1 && \
|
||||
mkdir -p /tmp/neo && cd /tmp/neo && \
|
||||
wget -q https://github.com/intel/intel-graphics-compiler/releases/download/v2.36.3/intel-igc-core-2_${IGC_VERSION}_amd64.deb \
|
||||
https://github.com/intel/intel-graphics-compiler/releases/download/v2.36.3/intel-igc-opencl-2_${IGC_VERSION}_amd64.deb \
|
||||
https://github.com/intel/compute-runtime/releases/download/${NEO_VERSION}/intel-opencl-icd_${NEO_VERSION}-0_amd64.deb \
|
||||
https://github.com/intel/compute-runtime/releases/download/${NEO_VERSION}/libigdgmm12_22.10.0_amd64.deb \
|
||||
https://github.com/intel/compute-runtime/releases/download/${NEO_VERSION}/libze-intel-gpu1_${NEO_VERSION}-0_amd64.deb && \
|
||||
dpkg -i *.deb && \
|
||||
rm -rf /tmp/neo && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
#============================================================================#
|
||||
# From here on, the Home Assistant integration layers are identical to the #
|
||||
# standard alexbelgium/birdnet-go add-on (which builds FROM the prebuilt #
|
||||
# upstream image). The only difference above is that the base is compiled #
|
||||
# from the fork + open PRs with OpenVINO enabled. #
|
||||
#============================================================================#
|
||||
|
||||
##################
|
||||
# 2 Modify Image #
|
||||
##################
|
||||
|
||||
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
||||
|
||||
# Set S6 wait time
|
||||
ENV S6_CMD_WAIT_FOR_SERVICES=1 \
|
||||
S6_CMD_WAIT_FOR_SERVICES_MAXTIME=0 \
|
||||
S6_SERVICES_GRACETIME=0
|
||||
|
||||
##################
|
||||
# 3 Install apps #
|
||||
##################
|
||||
|
||||
# Add rootfs
|
||||
COPY rootfs/ /
|
||||
RUN find . -type f \( -name "*.sh" -o -name "run" -o -name "finish" \) -print -exec chmod +x {} \;
|
||||
|
||||
# Silence "chmod: Read-only file system" noise from upstream entrypoint:
|
||||
# Home Assistant mounts /dev/snd read-only, so the chmod is a no-op and the
|
||||
# stderr output is just noise. The "|| true" already absorbs the exit code.
|
||||
# Warn (without failing the build) if the upstream pattern drifts so we notice
|
||||
# in CI logs and can update the patch.
|
||||
RUN if [ -f /usr/bin/entrypoint.sh ]; then \
|
||||
if grep -q 'chmod -R a+rw /dev/snd || true' /usr/bin/entrypoint.sh; then \
|
||||
sed -i 's#chmod -R a+rw /dev/snd || true#chmod -R a+rw /dev/snd 2>/dev/null || true#' /usr/bin/entrypoint.sh; \
|
||||
else \
|
||||
echo "WARN: upstream entrypoint.sh /dev/snd chmod pattern not found; nightly drift?" >&2; \
|
||||
fi; \
|
||||
fi
|
||||
|
||||
# Uses /bin for compatibility purposes
|
||||
# hadolint ignore=DL4005
|
||||
RUN if [ ! -f /bin/sh ] && [ -f /usr/bin/sh ]; then ln -s /usr/bin/sh /bin/sh; fi && \
|
||||
if [ ! -f /bin/bash ] && [ -f /usr/bin/bash ]; then ln -s /usr/bin/bash /bin/bash; fi
|
||||
|
||||
# Modules
|
||||
ARG MODULES="00-local_mounts.sh 00-smb_mounts.sh"
|
||||
|
||||
# Automatic modules download
|
||||
COPY ha_automodules.sh /ha_automodules.sh
|
||||
RUN chmod 744 /ha_automodules.sh && /ha_automodules.sh "$MODULES" && rm /ha_automodules.sh
|
||||
|
||||
# Manual apps
|
||||
ENV PACKAGES="alsa-utils libasound2-plugins mariadb-client nginx yq"
|
||||
|
||||
# Automatic apps & bashio
|
||||
COPY ha_autoapps.sh /ha_autoapps.sh
|
||||
RUN chmod 744 /ha_autoapps.sh && /ha_autoapps.sh "$PACKAGES" && rm /ha_autoapps.sh
|
||||
|
||||
################
|
||||
# 4 Entrypoint #
|
||||
################
|
||||
|
||||
# Add entrypoint
|
||||
ENV S6_STAGE2_HOOK=/ha_entrypoint.sh
|
||||
COPY ha_entrypoint.sh /ha_entrypoint.sh
|
||||
RUN chmod 777 /ha_entrypoint.sh
|
||||
|
||||
# Install bashio
|
||||
COPY bashio-standalone.sh /usr/local/lib/bashio-standalone.sh
|
||||
RUN chmod 0755 /usr/local/lib/bashio-standalone.sh
|
||||
|
||||
# Avoid config.yaml interference
|
||||
RUN sed -i "s|config.yaml|config_env.yaml|g" /etc/cont-init.d/01-config_yaml.sh
|
||||
ENTRYPOINT [ "/usr/bin/env" ]
|
||||
CMD [ "/ha_entrypoint.sh" ]
|
||||
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
||||
|
||||
############
|
||||
# 5 Labels #
|
||||
############
|
||||
|
||||
ARG BUILD_ARCH
|
||||
ARG BUILD_DATE
|
||||
ARG BUILD_DESCRIPTION
|
||||
ARG BUILD_NAME
|
||||
ARG BUILD_REF
|
||||
ARG BUILD_REPOSITORY
|
||||
ARG BUILD_VERSION
|
||||
ENV BUILD_VERSION="${BUILD_VERSION}"
|
||||
LABEL \
|
||||
io.hass.name="${BUILD_NAME}" \
|
||||
io.hass.description="${BUILD_DESCRIPTION}" \
|
||||
io.hass.arch="${BUILD_ARCH}" \
|
||||
io.hass.type="addon" \
|
||||
io.hass.version=${BUILD_VERSION} \
|
||||
maintainer="alexbelgium (https://github.com/alexbelgium)" \
|
||||
org.opencontainers.image.title="${BUILD_NAME}" \
|
||||
org.opencontainers.image.description="${BUILD_DESCRIPTION}" \
|
||||
org.opencontainers.image.vendor="Home Assistant Add-ons" \
|
||||
org.opencontainers.image.authors="alexbelgium (https://github.com/alexbelgium)" \
|
||||
org.opencontainers.image.licenses="MIT" \
|
||||
org.opencontainers.image.url="https://github.com/alexbelgium" \
|
||||
org.opencontainers.image.source="https://github.com/${BUILD_REPOSITORY}" \
|
||||
org.opencontainers.image.documentation="https://github.com/${BUILD_REPOSITORY}/blob/main/README.md" \
|
||||
org.opencontainers.image.created=${BUILD_DATE} \
|
||||
org.opencontainers.image.revision=${BUILD_REF} \
|
||||
org.opencontainers.image.version=${BUILD_VERSION}
|
||||
|
||||
#################
|
||||
# 6 Healthcheck #
|
||||
#################
|
||||
258
birdnet-go-dev/HAINTEGRATION.md
Normal file
@@ -0,0 +1,258 @@
|
||||
# BirdNET-Go Addon: Home Assistant Integration
|
||||
|
||||
BirdNET-Go can be integrated with Home Assistant using a MQTT Broker.
|
||||
|
||||
> **💡 Easiest path — automatic discovery.** If you run the Home Assistant
|
||||
> Mosquitto (MQTT) addon, just set `mqtt_auto_config: true` in this add-on's
|
||||
> options. The add-on then wires in the broker credentials **and** enables
|
||||
> BirdNET-Go's native Home Assistant MQTT auto-discovery, so the detection
|
||||
> sensors appear in Home Assistant automatically with **no manual YAML at
|
||||
> all**. The manual sensor/template/card configuration below is only needed if
|
||||
> you want to build your own custom entities instead of (or in addition to) the
|
||||
> auto-discovered ones.
|
||||
|
||||
## MQTT Configuration
|
||||
|
||||
Your Home Assistant must be setup with MQTT and BirdNET-Go MQTT integration must be enabled. Modify the BirdNET-Go config.yaml file to enable MQTT. If you are using the Mosquitto Broker addon, you will see a log message during the BirdNET-Go startup showing the internal MQTT server details needed for configuration similar to below.
|
||||
|
||||
```text
|
||||
BirdNET-Go log snipped showing MQTT details:
|
||||
/etc/cont-init.d/33-mqtt.sh: executing
|
||||
---
|
||||
MQTT addon is active on your system! Add the MQTT details below to the Birdnet-go config.yaml :
|
||||
MQTT user : addons
|
||||
MQTT password : Ri5ahV1aipeiw0aelerooteixai5ohtoeNg6oo3mo0thi5te0phiezuge4Phoore
|
||||
MQTT broker : tcp://core-mosquitto:1883
|
||||
---
|
||||
|
||||
Edit this section of config.yaml found in addon_configs/db21ed7f_birdnet-go/:
|
||||
mqtt:
|
||||
enabled: true # true to enable MQTT
|
||||
broker: tcp://core-mosquitto:1883 # MQTT (tcp://host:port)
|
||||
topic: birdnet # MQTT topic
|
||||
username: addons # MQTT username
|
||||
password: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # MQTT password
|
||||
```
|
||||
|
||||
## BirdNET-Go MQTT Sensors
|
||||
|
||||
Add the [MQTT sensor](https://www.home-assistant.io/integrations/sensor.mqtt/) yaml configuration below to your Home Assistant configuration.yaml file. Reload the configuration and once BirdNET-Go publishes a new finding to MQTT the new BirdNET-Go sensors should show that latest finding data.
|
||||
|
||||
```yaml
|
||||
mqtt:
|
||||
sensor:
|
||||
- name: "Birdnet-Go"
|
||||
state_topic: "birdnet"
|
||||
value_template: "{{ today_at(value_json.Time) }}"
|
||||
json_attributes_topic: "birdnet"
|
||||
json_attributes_template: "{{ value_json | tojson }}"
|
||||
- name: "Birdnet-Go Bird Image Url"
|
||||
state_topic: "birdnet"
|
||||
value_template: "{{ value_json.BirdImage.URL }}"
|
||||
- name: "Birdnet-Go Clip Name"
|
||||
state_topic: "birdnet"
|
||||
value_template: "{{ value_json.ClipName }}"
|
||||
- name: "Birdnet-Go Common Name"
|
||||
state_topic: "birdnet"
|
||||
value_template: "{{ value_json.CommonName }}"
|
||||
- name: "Birdnet-Go Confidence"
|
||||
state_topic: "birdnet"
|
||||
value_template: "{{ (value_json.Confidence | float * 100) | round(2) }}"
|
||||
unit_of_measurement: "%"
|
||||
- name: "Birdnet-Go Date"
|
||||
state_topic: "birdnet"
|
||||
value_template: "{{ value_json.Date }}"
|
||||
- name: "Birdnet-Go ProcessingTime"
|
||||
state_topic: "birdnet"
|
||||
value_template: "{{ (value_json.ProcessingTime | float / 1000000000 ) | round(4) }}"
|
||||
unit_of_measurement: "s"
|
||||
- name: "Birdnet-Go Scientific Name"
|
||||
state_topic: "birdnet"
|
||||
value_template: "{{ value_json.ScientificName }}"
|
||||
- name: "Birdnet-Go Sensitivity"
|
||||
state_topic: "birdnet"
|
||||
value_template: "{{ value_json.Sensitivity }}"
|
||||
- name: "Birdnet-Go Source"
|
||||
state_topic: "birdnet"
|
||||
value_template: "{{ value_json.Source }}"
|
||||
- name: "Birdnet-Go Species Code"
|
||||
state_topic: "birdnet"
|
||||
value_template: "{{ value_json.SpeciesCode }}"
|
||||
- name: "Birdnet-Go Threshold"
|
||||
state_topic: "birdnet"
|
||||
value_template: "{{ value_json.Threshold }}"
|
||||
- name: "Birdnet-Go Time"
|
||||
state_topic: "birdnet"
|
||||
value_template: "{{ today_at(value_json.Time) }}"
|
||||
```
|
||||
|
||||

|
||||
|
||||
## BirdNET-Go Events Sensor[^1]
|
||||
|
||||
Then create a new template sensor using the configuration below.
|
||||
|
||||
```yaml
|
||||
- trigger:
|
||||
- platform: mqtt
|
||||
topic: "birdnet"
|
||||
id: birdnet
|
||||
- platform: time
|
||||
at: "00:00:00"
|
||||
id: reset
|
||||
sensor:
|
||||
- unique_id: c893533c-3c06-4ebe-a5bb-da833da0a947
|
||||
name: BirdNET-Go Events
|
||||
state: >
|
||||
{% if trigger.id == 'reset' %}
|
||||
{{ now() }}
|
||||
{% elif trigger.id == 'birdnet' %}
|
||||
{{ today_at(trigger.payload_json.Time) }}
|
||||
{% endif %}
|
||||
attributes:
|
||||
bird_events: >
|
||||
{% if trigger.id == 'reset' %}
|
||||
{{ [] }}
|
||||
{% elif trigger.id == 'birdnet' %}
|
||||
{% set time = trigger.payload_json.Time %}
|
||||
{% set name = trigger.payload_json.CommonName %}
|
||||
{% set confidence = trigger.payload_json.Confidence|round(2) * 100 ~ '%' %}
|
||||
{% set current = this.attributes.get('bird_events', []) %}
|
||||
{% set new = dict(time=time, name=name, confidence=confidence) %}
|
||||
{{ current + [new] }}
|
||||
{% endif %}
|
||||
```
|
||||
|
||||
### BirdNET-Go Dashboard Cards
|
||||
|
||||
There are two versions listed below. The first example will link the Bird Name to Wikipedia. The other example will link to All About Birds. You will need to modify the Confidence link to match your Home Assistant setup.
|
||||
|
||||

|
||||
|
||||
```yaml
|
||||
type: markdown
|
||||
title: BirdNET (Wikipedia)
|
||||
content: >-
|
||||
Time| Bird Name|Number Today| Max
|
||||
[Confidence](http://ip_address_of_HA:8080/)
|
||||
|
||||
:---|:---|:---:|:---:
|
||||
|
||||
{%- set t = now() %}
|
||||
|
||||
{%- set bird_list = state_attr('sensor.birdnet_go_events','bird_events') |
|
||||
sort(attribute='time', reverse=true) | map(attribute='name') | unique | list
|
||||
%}
|
||||
|
||||
{%- set bird_objects = state_attr('sensor.birdnet_go_events','bird_events') |
|
||||
sort(attribute='time', reverse=true) %}
|
||||
|
||||
{%- for thisbird in bird_list or [] %}
|
||||
|
||||
{%- set ubird = ((bird_objects | selectattr("name", "equalto", thisbird)) |
|
||||
list)[0] %}
|
||||
|
||||
{%- set ubird_count = ((bird_objects | selectattr("name", "equalto",
|
||||
thisbird)) | list) | length %}
|
||||
|
||||
{%- set ubird_max_confidence = ((bird_objects | selectattr("name", "equalto",
|
||||
thisbird)) | map(attribute='confidence') | map('replace', '%', '') |
|
||||
map('float') | max | round(0)) %}
|
||||
|
||||
{%- if ubird_max_confidence > 70 %}
|
||||
|
||||
{{ubird.time}}
|
||||
| [{{ubird.name}}](https://en.wikipedia.org/wiki/{{ubird.name |
|
||||
replace(' ', '_')}}) | {{ubird_count}} | {{ ubird_max_confidence }} %
|
||||
|
||||
{%- endif %}
|
||||
|
||||
{%- endfor %}
|
||||
card_mod:
|
||||
style:
|
||||
$: |
|
||||
.card-header {
|
||||
display: flex !important;
|
||||
align-items: center;
|
||||
}
|
||||
.card-header:before {
|
||||
content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='m23 11.5l-3.05-1.13c-.26-1.15-.91-1.81-.91-1.81a4.19 4.19 0 0 0-5.93 0l-1.48 1.48L5 3c-1 4 0 8 2.45 11.22L2 19.5s8.89 2 14.07-2.05c2.76-2.16 3.38-3.42 3.77-4.75zm-5.29.22c-.39.39-1.03.39-1.42 0a.996.996 0 0 1 0-1.41c.39-.39 1.03-.39 1.42 0s.39 1.02 0 1.41'/%3E%3C/svg%3E");
|
||||
height: 42px;
|
||||
width: 42px;
|
||||
margin-top: 0px;
|
||||
padding-left: 0px;
|
||||
padding-right: 14px;
|
||||
}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.card-header:before {
|
||||
content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23E1E1E1' d='m23 11.5l-3.05-1.13c-.26-1.15-.91-1.81-.91-1.81a4.19 4.19 0 0 0-5.93 0l-1.48 1.48L5 3c-1 4 0 8 2.45 11.22L2 19.5s8.89 2 14.07-2.05c2.76-2.16 3.38-3.42 3.77-4.75zm-5.29.22c-.39.39-1.03.39-1.42 0a.996.996 0 0 1 0-1.41c.39-.39 1.03-.39 1.42 0s.39 1.02 0 1.41'/%3E%3C/svg%3E");
|
||||
height: 42px;
|
||||
width: 42px;
|
||||
margin-top: 0px;
|
||||
padding-left: 0px;
|
||||
padding-right: 14px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||

|
||||
|
||||
```yaml
|
||||
type: markdown
|
||||
title: BirdNET (All About Birds)
|
||||
content: >-
|
||||
Time| Bird Name|Number Today| Max
|
||||
[Confidence](http://ip_address_of_HA:8080/)
|
||||
|
||||
:---|:---|:---:|:---:
|
||||
|
||||
{%- set t = now() %}
|
||||
|
||||
{%- set bird_list = state_attr('sensor.birdnet_go_events','bird_events') |
|
||||
sort(attribute='time', reverse=true) | map(attribute='name') | unique | list
|
||||
%}
|
||||
|
||||
{%- set bird_objects = state_attr('sensor.birdnet_go_events','bird_events') |
|
||||
sort(attribute='time', reverse=true) %}
|
||||
|
||||
{%- for thisbird in bird_list or [] %}
|
||||
|
||||
{%- set ubird = ((bird_objects | selectattr("name", "equalto", thisbird)) |
|
||||
list)[0] %}
|
||||
|
||||
{%- set ubird_count = ((bird_objects | selectattr("name", "equalto",
|
||||
thisbird)) | list) | length %}
|
||||
|
||||
{%- set ubird_max_confidence = ((bird_objects | selectattr("name", "equalto",
|
||||
thisbird)) | map(attribute='confidence') | map('replace', '%', '') |
|
||||
map('float') | max | round(0)) %}
|
||||
|
||||
{%- if ubird_max_confidence > 70 %}
|
||||
|
||||
{{ubird.time}}
|
||||
| [{{ubird.name}}](https://www.allaboutbirds.org/guide/{{ubird.name
|
||||
| replace(' ', '_')}}) | {{ubird_count}} | {{ ubird_max_confidence }} %
|
||||
|
||||
{%- endif %}
|
||||
|
||||
{%- endfor %}
|
||||
card_mod:
|
||||
style:
|
||||
$: |
|
||||
.card-header {
|
||||
display: flex !important;
|
||||
align-items: center;
|
||||
}
|
||||
.card-header:before {
|
||||
content: url("data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyMDYuODcgMTE2LjY2Ij48ZGVmcz48c3R5bGU+LmNscy0xe2ZpbGw6I2Y0ZTUwNTt9LmNscy0ye2ZpbGw6I2UzMWUyNjt9LmNscy0ze2ZpbGw6I2ZmZjt9PC9zdHlsZT48L2RlZnM+PHBhdGggZD0iTTIwNi4zNywxNi42OHMtMTYuNDQtNC4zNC0yMi43Ni00LjljMCwwLTI1LDEzLjUtMzIsMThhMTkuMTYsMTkuMTYsMCwwLDAtOC42NywxMy44OWwzNS43MS0yNi4zMmgyOEMyMDcuMzEsMTcuMzksMjA2LjM3LDE2LjY4LDIwNi4zNywxNi42OFoiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAgMC42MykiLz48cGF0aCBkPSJNMTQ4LjU1LDI3LjMzYzcuMzItNC45LDMyLjYyLTE4LjczLDMyLjYyLTE4LjczbDAsMEEzMC42OSwzMC42OSwwLDAsMCwxNTktLjYzYTQ0LjIzLDQ0LjIzLDAsMCwwLTIwLjcxLDVIMGMwLDMuNzEsNS42LDYuNTYsMTIuMTQsNi41Nkg1Mi4zNkw4Ni42MiwzNS4xMlY3MS4zN2MwLDE1LjczLDguMjYsMjkuNDQsMjEuNzgsMzcuMzVTMTI4LjY4LDExNiwxMzguNjMsMTE2VjQ2Ljg3QzEzOC42Myw0MC43OCwxNDAuNDcsMzIuNzMsMTQ4LjU1LDI3LjMzWk0xNjcuODcsOGEyLjUxLDIuNTEsMCwxLDEtMi41MSwyLjUxQTIuNTEsMi41MSwwLDAsMSwxNjcuODcsOFptLTI5LjEzLDEzLDE1LjY5LTguNjgsNi44OS41N0wxMzguNzQsMjUuMzZaIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwIDAuNjMpIi8+PHBhdGggY2xhc3M9ImNscy0xIiBkPSJNNTIuMzYsMTAuOTFIMTEwYy0xMi44OSwwLTIzLjQsMTAuMzUtMjMuNCwyNC4yMVoiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAgMC42MykiLz48cGF0aCBjbGFzcz0iY2xzLTIiIGQ9Ik0xNzgsMTAuMzNBMzEuNzEsMzEuNzEsMCwwLDAsMTU3Ljc4LDIuOVYtLjYxbDEuMjUsMEEzMC42MywzMC42MywwLDAsMSwxODEuMTcsOC42WiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAwLjYzKSIvPjxwYXRoIGNsYXNzPSJjbHMtMiIgZD0iTTE3OC42MywxNy4zOWwtMjUsMTguNDNzLS4yOS0yLjcsMy40Ny01Ljc0LDI2LjUtMTguMywyNi41LTE4LjNaIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwIDAuNjMpIi8+PHBhdGggY2xhc3M9ImNscy0zIiBkPSJNMTI4LjE0LDY0LjQ3VjUyLjE1YzAtNS4xOC0yLjExLTguNzctNi45My0xMi4xOEwxMDAuNzksMjUuNTRhMTQuMzIsMTQuMzIsMCwwLDAsMiwyMVoiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAgMC42MykiLz48cGF0aCBjbGFzcz0iY2xzLTMiIGQ9Ik0xMjguMTQsNjQuNDdWNTIuMTVjMC01LjE4LTIuMTEtOC43Ny02LjkzLTEyLjE4TDEwMC43OSwyNS41NGExNC4zMiwxNC4zMiwwLDAsMCwyLDIxWiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAwLjYzKSIvPjxwYXRoIGNsYXNzPSJjbHMtMyIgZD0iTTE1MS41OSwyOS44MmM3LTQuNTQsMzItMTgsMzItMThhMTYuMjQsMTYuMjQsMCwwLDAtMi40MS0zLjE1bDAsMHMtMjUuMywxMy44My0zMi42MiwxOC43My05LjU3LDEyLjE3LTkuODcsMThsLS4wNSwxLjUxLDQuMjktMy4xNkExOS4xNiwxOS4xNiwwLDAsMSwxNTEuNTksMjkuODJaIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwIDAuNjMpIi8+PHBhdGggY2xhc3M9ImNscy0zIiBkPSJNMTY3Ljg3LDhhMi41MSwyLjUxLDAsMSwxLTIuNTEsMi41MUEyLjUxLDIuNTEsMCwwLDEsMTY3Ljg3LDhaIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwIDAuNjMpIi8+PHBvbHlnb24gY2xhc3M9ImNscy0zIiBwb2ludHM9IjEzOC43NCAyMS41NyAxNTQuNDMgMTIuODkgMTYxLjMyIDEzLjQ1IDEzOC43NCAyNS45OCAxMzguNzQgMjEuNTciLz48L3N2Zz4=");
|
||||
height: 20px;
|
||||
width: 60px;
|
||||
margin-top: -10px;
|
||||
padding-left: 8px;
|
||||
padding-right: 18px;
|
||||
}
|
||||
```
|
||||
|
||||
## Footnotes
|
||||
|
||||
[^1]: [Displaying Birdnet-go detections](https://community.home-assistant.io/t/displaying-birdnet-go-detections/713611/22)
|
||||
177
birdnet-go-dev/README.md
Normal file
@@ -0,0 +1,177 @@
|
||||
# Home assistant add-on: Birdnet-Go (from source)
|
||||
|
||||
> **⚠️ Test build.** This is a special variant of the [standard birdnet-go add-on](https://github.com/alexbelgium/hassio-addons/tree/master/birdnet-go). Instead of pulling the prebuilt `ghcr.io/tphakala/birdnet-go` image, it **compiles BirdNET-Go from the [`alexbelgium/birdnet-go`](https://github.com/alexbelgium/birdnet-go) fork**. At build time it syncs the fork's `main` with the `tphakala/birdnet-go` upstream and **merges every open non-draft ("in review") pull request on the fly** (see [`merge-prs.sh`](./merge-prs.sh)), so the binary reflects upstream main plus all work currently under review. Everything below is identical to the standard add-on.
|
||||
|
||||
|
||||
|
||||
I maintain this and other Home Assistant add-ons in my free time: keeping up with upstream changes, HA changes, and testing on real hardware takes a lot of time (and some money). I use around 5-10 of my >110 addons so regularly I install test machines (and purchase some test services such as vpn) that I don't use myself to troubleshoot and improve the addons
|
||||
|
||||
If this add-on saves you time or makes your setup easier, I would be very grateful for your support!
|
||||
|
||||
[![Buy me a coffee][donation-badge]](https://www.buymeacoffee.com/alexbelgium)
|
||||
[![Donate via PayPal][paypal-badge]](https://www.paypal.com/donate/?hosted_button_id=DZFULJZTP3UQA)
|
||||
|
||||
## Addon informations
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
[](https://www.codacy.com/gh/alexbelgium/hassio-addons/dashboard?utm_source=github.com&utm_medium=referral&utm_content=alexbelgium/hassio-addons&utm_campaign=Badge_Grade)
|
||||
[](https://github.com/alexbelgium/hassio-addons/actions/workflows/weekly-supelinter.yaml)
|
||||
[](https://github.com/alexbelgium/hassio-addons/actions/workflows/onpush_builder.yaml)
|
||||
|
||||
[donation-badge]: https://img.shields.io/badge/Buy%20me%20a%20coffee-%23d32f2f?logo=buy-me-a-coffee&style=flat&logoColor=white
|
||||
[paypal-badge]: https://img.shields.io/badge/Donate%20via%20PayPal-0070BA?logo=paypal&style=flat&logoColor=white
|
||||
|
||||
_Thanks to everyone having starred my repo! To star it click on the image below, then it will be on top right. Thanks!_
|
||||
|
||||
[](https://github.com/alexbelgium/hassio-addons/stargazers)
|
||||
|
||||
|
||||

|
||||
|
||||
## About
|
||||
|
||||
[BirdNET-Go](https://github.com/tphakala/birdnet-go/tree/main) is an AI solution for continuous avian monitoring and identification developed by @tphakala
|
||||
|
||||
This addon is based on their docker image.
|
||||
|
||||
## Configuration
|
||||
|
||||
Install, then start the addon a first time. Webui can be found at <http://homeassistant:8080>.
|
||||
You'll need a microphone : either use one connected to HA or the audio stream of a rstp camera.
|
||||
|
||||
The audio clips folder can be stored on an external or SMB drive by mounting it from the addon options, then specifying the path instead of "clips/". For example, "/mnt/NAS/Birdnet/"
|
||||
|
||||
Options can be configured through three ways :
|
||||
|
||||
- Addon options
|
||||
|
||||
```yaml
|
||||
BIRDSONGS_FOLDER: /config/clips # where audio clips are stored (can be on a mounted drive)
|
||||
LOG_MAX_SIZE_MB: 50 # max log file size before rotation
|
||||
LOG_MAX_AGE_DAYS: 7 # max log retention in days
|
||||
homeassistant_microphone: false # when true, force audio source to "default" (HA microphone)
|
||||
env_vars: [] # extra environment variables to pass to the container
|
||||
TZ: Etc/UTC # timezone, see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List
|
||||
mqtt_auto_config: false # set true to auto-wire the Home Assistant MQTT addon into config.yaml
|
||||
mariadb_auto_config: false # set true to auto-wire the Home Assistant MariaDB addon into config.yaml (also disables SQLite)
|
||||
```
|
||||
|
||||
- Config.yaml
|
||||
Additional variables can be configured using the config.yaml file found in /config/db21ed7f_birdnet-go/config.yaml using the Filebrowser addon
|
||||
|
||||
- Config_env.yaml
|
||||
Additional environment variables can be configured there
|
||||
|
||||
### MQTT and MariaDB auto-configuration (opt-in)
|
||||
|
||||
If the Home Assistant **MQTT** addon is installed and running and you set `mqtt_auto_config: true` in the addon options, the addon writes the HA Mosquitto credentials directly into BirdNET-Go's `config.yaml` on every startup: `realtime.mqtt.enabled`, `broker`, `username`, and `password` are populated, and the topic defaults to `birdnet`. In addition, it enables BirdNET-Go's **native Home Assistant MQTT auto-discovery** (`realtime.mqtt.homeassistant.enabled`), so the detection sensors show up in Home Assistant automatically — **no manual MQTT sensor YAML required** (the hand-written sensors in [HAINTEGRATION.md](./HAINTEGRATION.md) remain available if you prefer to build your own). Messages are also retained (`realtime.mqtt.retain: true`) so sensor states survive Home Assistant restarts. When the option is `false` (the default), the addon still logs the broker details and reminds you about the option whenever Mosquitto is detected — nothing is written.
|
||||
|
||||
If the Home Assistant **MariaDB** addon is installed and running and you set `mariadb_auto_config: true`, the addon writes the HA credentials into `output.mysql.*` and sets `output.sqlite.enabled` to `false` (database name `birdnet`, created on first connect). When the option is `false` (the default), the addon only logs the credentials so you can configure them manually.
|
||||
|
||||
The addon also seeds `output.sqlite.path` and `logging.file_output.*` defaults only when those keys are missing from `config.yaml`, so values you change through the BirdNET-Go UI now survive container restarts.
|
||||
|
||||
### Mounting Drives
|
||||
|
||||
This addon supports mounting both local drives and remote SMB shares:
|
||||
|
||||
- **Local drives**: See [Mounting Local Drives in Addons](https://github.com/alexbelgium/hassio-addons/wiki/Mounting-Local-Drives-in-Addons)
|
||||
- **Remote shares**: See [Mounting Remote Shares in Addons](https://github.com/alexbelgium/hassio-addons/wiki/Mounting-remote-shares-in-Addons)
|
||||
|
||||
### Custom Scripts and Environment Variables
|
||||
|
||||
This addon supports custom scripts and environment variables through the `addon_config` mapping:
|
||||
|
||||
- **Custom scripts**: See [Running Custom Scripts in Addons](https://github.com/alexbelgium/hassio-addons/wiki/Running-custom-scripts-in-Addons)
|
||||
- **env_vars option**: Use the add-on `env_vars` option to pass extra environment variables (uppercase or lowercase names). See https://github.com/alexbelgium/hassio-addons/wiki/Add-Environment-variables-to-your-Addon-2 for details.
|
||||
|
||||
## Installation
|
||||
|
||||
The installation of this add-on is pretty straightforward and not different in comparison to installing any other add-on.
|
||||
|
||||
1. Add my add-ons repository to your home assistant instance (in supervisor addons store at top right, or click button below if you have configured my HA)
|
||||
|
||||
[](https://my.home-assistant.io/redirect/supervisor_add_addon_repository/?repository_url=https%3A%2F%2Fgithub.com%2Falexbelgium%2Fhassio-addons)
|
||||
1. Install this add-on.
|
||||
1. Click the `Save` button to store your configuration.
|
||||
1. Set the add-on options to your preferences
|
||||
1. Start the add-on.
|
||||
1. Check the logs of the add-on to see if everything went well.
|
||||
1. Open the webUI and adapt the software options
|
||||
|
||||
## Integration with HA
|
||||
|
||||
Home Assistant Integration instructions are found here, [Birdnet-Go Addon: Home Assistant Integration](./HAINTEGRATION.md)
|
||||
|
||||
## Setting up a RTSP Source using VLC
|
||||
|
||||
VLC opens a TCP port but the stream is udp. Because of this will need to configure Birdnet-Go to use udp. Adjust the config.yaml file to udp or use the birdnet-go command line option:
|
||||
|
||||
`--rtsptransport udp --rtsp rtsp://192.168.1.21:8080/stream.sdp`
|
||||
|
||||
### Linux instructions
|
||||
|
||||
Run vlc without an interface using one of these commands:
|
||||
|
||||
```bash
|
||||
# This should work for most devices
|
||||
/usr/bin/vlc -I dummy -vvv alsa://hw:0,0 --no-sout-all --sout-keep --sout '#transcode{acodec=mpga}:rtp{sdp=rtsp://:8080/stream.sdp}'
|
||||
|
||||
# Try this if the first command does not work
|
||||
/usr/bin/vlc -I dummy -vvv alsa://hw:4,0 --no-sout-all --sout-keep --sout '#rtp{sdp=rtsp://:8080/stream.sdp}'
|
||||
```
|
||||
|
||||
Run `arecord -l` to get microphone hardware info
|
||||
|
||||
```text
|
||||
**** List of CAPTURE Hardware Devices ****
|
||||
card 0: PCH [HDA Intel PCH], device 0: ALC3220 Analog [ALC3220 Analog]
|
||||
Subdevices: 1/1
|
||||
Subdevice #0: subdevice #0
|
||||
card 2: S7 [SteelSeries Arctis 7], device 0: USB Audio [USB Audio]
|
||||
Subdevices: 1/1
|
||||
Subdevice #0: subdevice #0
|
||||
card 3: Nano [Yeti Nano], device 0: USB Audio [USB Audio]
|
||||
Subdevices: 1/1
|
||||
Subdevice #0: subdevice #0
|
||||
card 4: Device [USB PnP Sound Device], device 0: USB Audio [USB Audio]
|
||||
Subdevices: 0/1
|
||||
Subdevice #0: subdevice #0
|
||||
```
|
||||
|
||||
hw:4,0 = **card 4**: Device [USB PnP Sound Device], **device 0**: USB Audio [USB Audio]
|
||||
|
||||
Systemd service file example. Adjust the user:group accordingly. If you want to run as root, you will likely need to run vlc-wrapper instead of vlc.
|
||||
|
||||
```text
|
||||
[Unit]
|
||||
Description=VLC Birdnet RTSP Server
|
||||
Wants=network-online.target
|
||||
After=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
StandardOutput=journal
|
||||
ExecStart=/usr/bin/vlc -I dummy -vvv alsa://hw:0,0 --sout '#transcode{acodec=mpga}:rtp{sdp=rtsp://:8080/stream.sdp}'
|
||||
User=someone
|
||||
Group=somegroup
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
## Common issues
|
||||
|
||||
Not yet available
|
||||
|
||||
## Support
|
||||
|
||||
Create an issue on github
|
||||
|
||||
---
|
||||
|
||||

|
||||
|
||||
|
||||
67
birdnet-go-dev/apparmor.txt
Normal file
@@ -0,0 +1,67 @@
|
||||
#include <tunables/global>
|
||||
|
||||
profile db21ed7f_birdnet-go flags=(attach_disconnected,mediate_deleted) {
|
||||
#include <abstractions/base>
|
||||
|
||||
capability chown,
|
||||
capability dac_override,
|
||||
capability dac_read_search,
|
||||
capability fowner,
|
||||
capability setgid,
|
||||
capability setuid,
|
||||
capability sys_admin,
|
||||
capability sys_resource,
|
||||
file,
|
||||
signal,
|
||||
mount,
|
||||
umount,
|
||||
remount,
|
||||
network udp,
|
||||
network tcp,
|
||||
network dgram,
|
||||
network stream,
|
||||
network inet,
|
||||
network inet6,
|
||||
network netlink raw,
|
||||
network unix dgram,
|
||||
|
||||
|
||||
# S6-Overlay
|
||||
/init ix,
|
||||
/run/{s6,s6-rc*,service}/** ix,
|
||||
/package/** ix,
|
||||
/command/** ix,
|
||||
/run/{,**} rwk,
|
||||
/dev/tty rw,
|
||||
/bin/** ix,
|
||||
/usr/bin/** ix,
|
||||
/usr/lib/bashio/** ix,
|
||||
/etc/s6/** rix,
|
||||
/run/s6/** rix,
|
||||
/etc/services.d/** rwix,
|
||||
/etc/cont-init.d/** rwix,
|
||||
/etc/cont-finish.d/** rwix,
|
||||
/init rix,
|
||||
/var/run/** mrwkl,
|
||||
/var/run/ mrwkl,
|
||||
/dev/i2c-1 mrwkl,
|
||||
# Files required
|
||||
/dev/fuse mrwkl,
|
||||
/dev/sda1 mrwkl,
|
||||
/dev/sdb1 mrwkl,
|
||||
/dev/nvme0 mrwkl,
|
||||
/dev/nvme1 mrwkl,
|
||||
/dev/mmcblk0p1 mrwkl,
|
||||
/dev/* mrwkl,
|
||||
/tmp/** mrkwl,
|
||||
|
||||
# Data access
|
||||
/data/** rw,
|
||||
|
||||
# suppress ptrace denials when using 'docker ps' or using 'ps' inside a container
|
||||
ptrace (trace,read) peer=docker-default,
|
||||
|
||||
# docker daemon confinement requires explict allow rule for signal
|
||||
signal (receive) set=(kill,term) peer=/usr/bin/docker,
|
||||
|
||||
}
|
||||
131
birdnet-go-dev/config.yaml
Normal file
@@ -0,0 +1,131 @@
|
||||
arch:
|
||||
- amd64
|
||||
audio: true
|
||||
backup_exclude:
|
||||
- logs/**
|
||||
description: Realtime BirdNET soundscape analyzer, compiled from the alexbelgium/birdnet-go fork with all open PRs merged, with OpenVINO enabled for Intel CPU/iGPU acceleration (amd64-only test build)
|
||||
devices:
|
||||
- /dev/dri
|
||||
- /dev/snd
|
||||
- /dev/snd/controlC0
|
||||
- /dev/snd/controlC1
|
||||
- /dev/snd/pcmC1D0c
|
||||
- /dev/snd/pcmC1D0p
|
||||
- /dev/dri/card0
|
||||
- /dev/dri/card1
|
||||
- /dev/dri/renderD128
|
||||
- /dev/vchiq
|
||||
- /dev/video10
|
||||
- /dev/video11
|
||||
- /dev/video12
|
||||
- /dev/video13
|
||||
- /dev/video14
|
||||
- /dev/video15
|
||||
- /dev/video16
|
||||
- /dev/ttyUSB0
|
||||
- /dev/sda
|
||||
- /dev/sdb
|
||||
- /dev/sdc
|
||||
- /dev/sdd
|
||||
- /dev/sde
|
||||
- /dev/sdf
|
||||
- /dev/sdg
|
||||
- /dev/nvme
|
||||
- /dev/nvme0
|
||||
- /dev/nvme0n1
|
||||
- /dev/nvme0n1p1
|
||||
- /dev/nvme0n1p2
|
||||
- /dev/nvme0n1p3
|
||||
- /dev/nvme1n1
|
||||
- /dev/nvme1n1p1
|
||||
- /dev/nvme1n1p2
|
||||
- /dev/nvme1n1p3
|
||||
- /dev/nvme2n1
|
||||
- /dev/nvme2n1p1
|
||||
- /dev/nvme2n1p2
|
||||
- /dev/nvme2n3p3
|
||||
- /dev/mmcblk
|
||||
- /dev/fuse
|
||||
- /dev/sda1
|
||||
- /dev/sdb1
|
||||
- /dev/sdc1
|
||||
- /dev/sdd1
|
||||
- /dev/sde1
|
||||
- /dev/sdf1
|
||||
- /dev/sdg1
|
||||
- /dev/sda2
|
||||
- /dev/sdb2
|
||||
- /dev/sdc2
|
||||
- /dev/sdd2
|
||||
- /dev/sde2
|
||||
- /dev/sdf2
|
||||
- /dev/sdg2
|
||||
- /dev/sda3
|
||||
- /dev/sdb3
|
||||
- /dev/sda4
|
||||
- /dev/sdb4
|
||||
- /dev/sda5
|
||||
- /dev/sda6
|
||||
- /dev/sda7
|
||||
- /dev/sda8
|
||||
- /dev/nvme0
|
||||
- /dev/nvme1
|
||||
- /dev/nvme2
|
||||
environment:
|
||||
BIRDNET_GID: "0"
|
||||
BIRDNET_UID: "0"
|
||||
image: ghcr.io/alexbelgium/birdnet-go-dev-{arch}
|
||||
ingress: true
|
||||
ingress_entry: "ui/dashboard"
|
||||
ingress_stream: true
|
||||
init: false
|
||||
map:
|
||||
- addon_config:rw
|
||||
- media:rw
|
||||
- share:rw
|
||||
name: Birdnet-go (custom version)
|
||||
options:
|
||||
env_vars: []
|
||||
BIRDSONGS_FOLDER: /config/clips
|
||||
LOG_MAX_SIZE_MB: 50
|
||||
LOG_MAX_AGE_DAYS: 7
|
||||
homeassistant_microphone: false
|
||||
mqtt_auto_config: false
|
||||
mariadb_auto_config: false
|
||||
panel_admin: false
|
||||
panel_icon: mdi:bird
|
||||
ports:
|
||||
8080/tcp: 8080
|
||||
9090/tcp: 9090
|
||||
ports_description:
|
||||
8080/tcp: Web ui
|
||||
9090/tcp: Telemetry endpoint
|
||||
privileged:
|
||||
- SYS_ADMIN
|
||||
- DAC_READ_SEARCH
|
||||
- SYS_RESOURCE
|
||||
schema:
|
||||
env_vars:
|
||||
- name: match(^[A-Za-z0-9_]+$)
|
||||
value: str?
|
||||
BIRDSONGS_FOLDER: str?
|
||||
LOG_MAX_SIZE_MB: int(1,1000)?
|
||||
LOG_MAX_AGE_DAYS: int(1,365)?
|
||||
TZ: str?
|
||||
cifsdomain: str?
|
||||
cifspassword: str?
|
||||
cifsusername: str?
|
||||
homeassistant_microphone: bool?
|
||||
localdisks: str?
|
||||
mariadb_auto_config: bool?
|
||||
mqtt_auto_config: bool?
|
||||
networkdisks: str?
|
||||
services:
|
||||
- mysql:want
|
||||
- mqtt:want
|
||||
slug: birdnet-go-dev
|
||||
udev: true
|
||||
url: https://github.com/alexbelgium/hassio-addons
|
||||
usb: true
|
||||
version: "source-20260708-2"
|
||||
video: true
|
||||
BIN
birdnet-go-dev/icon.png
Normal file
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 11 KiB |
BIN
birdnet-go-dev/images/ha_birdnet_markdown_card_wikipedia.png
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
BIN
birdnet-go-dev/images/ha_birdnet_mqtt_sensor.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
birdnet-go-dev/logo.png
Normal file
|
After Width: | Height: | Size: 35 KiB |
88
birdnet-go-dev/merge-prs.sh
Executable file
@@ -0,0 +1,88 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Build-time helper for the BirdNET-Go "from source" Home Assistant add-on.
|
||||
#
|
||||
# Clones the alexbelgium/birdnet-go fork, fast-forwards its main onto the
|
||||
# tphakala/birdnet-go upstream (so main is fully synced with upstream), then
|
||||
# merges every OPEN, NON-DRAFT ("in review") pull request on top - producing a
|
||||
# source tree that is upstream main plus all work currently under review.
|
||||
#
|
||||
# The merged tree (including .git, which the BirdNET-Go build uses for version
|
||||
# stamping) is written to the directory given as $1 so the Docker build can
|
||||
# compile it.
|
||||
#
|
||||
# Environment:
|
||||
# BIRDNET_FORK owner/repo of the fork (default alexbelgium/birdnet-go)
|
||||
# BIRDNET_UPSTREAM owner/repo of the upstream (default tphakala/birdnet-go)
|
||||
# GH_TOKEN / GITHUB_TOKEN optional, lifts the 60 req/h unauthenticated
|
||||
# GitHub API rate limit; not required for public repos
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
TARGET_DIR="${1:?usage: merge-prs.sh <target-dir>}"
|
||||
|
||||
FORK="${BIRDNET_FORK:-alexbelgium/birdnet-go}"
|
||||
UPSTREAM="${BIRDNET_UPSTREAM:-tphakala/birdnet-go}"
|
||||
|
||||
FORK_URL="https://github.com/${FORK}.git"
|
||||
UPSTREAM_URL="https://github.com/${UPSTREAM}.git"
|
||||
API_URL="https://api.github.com/repos/${FORK}/pulls?state=open&per_page=100"
|
||||
|
||||
# Optional token to lift the unauthenticated GitHub API rate limit.
|
||||
GH_TOKEN="${GH_TOKEN:-${GITHUB_TOKEN:-}}"
|
||||
|
||||
log() { echo ">>> $*"; }
|
||||
|
||||
git config --global user.email "addon-builder@users.noreply.github.com"
|
||||
git config --global user.name "BirdNET-Go Addon Builder"
|
||||
git config --global advice.detachedHead false
|
||||
|
||||
log "Cloning fork ${FORK}"
|
||||
git clone "${FORK_URL}" "${TARGET_DIR}"
|
||||
cd "${TARGET_DIR}"
|
||||
git checkout main
|
||||
|
||||
log "Syncing main with upstream ${UPSTREAM}"
|
||||
git remote add upstream "${UPSTREAM_URL}"
|
||||
git fetch --no-tags upstream main
|
||||
# --no-ff keeps an explicit sync commit; a no-op when main is already current.
|
||||
git merge --no-edit --no-ff upstream/main
|
||||
|
||||
log "Querying open non-draft PRs from ${FORK}"
|
||||
auth_header=()
|
||||
if [ -n "${GH_TOKEN}" ]; then
|
||||
auth_header=(-H "Authorization: Bearer ${GH_TOKEN}")
|
||||
fi
|
||||
|
||||
pr_json="$(curl -fsSL "${auth_header[@]}" \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
"${API_URL}")"
|
||||
|
||||
# Open, non-draft PRs only ("in review"), oldest first for a stable merge order.
|
||||
mapfile -t prs < <(echo "${pr_json}" \
|
||||
| jq -r 'sort_by(.number) | .[] | select(.draft == false) | "\(.number)\t\(.head.sha)\t\(.title)"')
|
||||
|
||||
if [ "${#prs[@]}" -eq 0 ]; then
|
||||
log "No open non-draft PRs to merge - building upstream-synced main only"
|
||||
else
|
||||
log "Merging ${#prs[@]} open non-draft PR(s)"
|
||||
fi
|
||||
|
||||
for entry in "${prs[@]}"; do
|
||||
number="$(printf '%s' "${entry}" | cut -f1)"
|
||||
sha="$(printf '%s' "${entry}" | cut -f2)"
|
||||
title="$(printf '%s' "${entry}" | cut -f3-)"
|
||||
log "Merging PR #${number}: ${title} (${sha})"
|
||||
# Fetch the PR head commit by number; works unauthenticated for public repos.
|
||||
git fetch --no-tags origin "refs/pull/${number}/head"
|
||||
if ! git merge --no-edit --no-ff -m "Merge PR #${number}: ${title}" "${sha}"; then
|
||||
echo "!!! Merge conflict while merging PR #${number} (${title})." >&2
|
||||
echo "!!! Resolve the conflict in the fork or pause this PR, then rebuild." >&2
|
||||
git merge --abort || true
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
log "Merged HEAD: $(git rev-parse --short HEAD)"
|
||||
log "Source tree ready at ${TARGET_DIR}"
|
||||
194
birdnet-go-dev/rootfs/etc/cont-init.d/01-structure.sh
Executable file
@@ -0,0 +1,194 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
set -e
|
||||
|
||||
# Default Variables
|
||||
DEFAULT_BIRDSONGS_FOLDER="/data/clips"
|
||||
CONFIG_LOCATION="/config/config.yaml"
|
||||
|
||||
# Strip trailing slashes; canonical internal form has none.
|
||||
normalize_path() {
|
||||
local p="$1"
|
||||
while [[ "$p" == */ && "$p" != "/" ]]; do
|
||||
p="${p%/}"
|
||||
done
|
||||
printf '%s' "$p"
|
||||
}
|
||||
|
||||
# Reject paths containing characters that would break the SQL/YAML literals
|
||||
# we substitute into below. We deliberately allow only "safe" filename chars.
|
||||
# Also reject ".." path segments so a relative path can't traverse outside
|
||||
# the directory we prefix it with (e.g. "/config") when we rewrite it below.
|
||||
validate_safe_path() {
|
||||
local p="$1"
|
||||
if [[ ! "$p" =~ ^[A-Za-z0-9._/-]+$ ]]; then
|
||||
bashio::log.fatal "Refusing unsafe path: '$p' (only [A-Za-z0-9._/-] allowed)"
|
||||
exit 1
|
||||
fi
|
||||
local segment
|
||||
local IFS=/
|
||||
for segment in $p; do
|
||||
if [[ "$segment" == ".." ]]; then
|
||||
bashio::log.fatal "Refusing unsafe path: '$p' (path traversal '..' is not allowed)"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
if [ ! -f "$CONFIG_LOCATION" ]; then
|
||||
bashio::log.warning "There is no config.yaml yet in the config folder, downloading a default one. Please customize"
|
||||
# Network may be unreachable on first boot. If the download fails, seed
|
||||
# an empty YAML document so the yq reads/writes below succeed and the
|
||||
# default-value seeding logic later in this script populates a usable
|
||||
# config. (We can't remove the file and continue — subsequent yq calls
|
||||
# under set -e would abort the init script.)
|
||||
if ! curl -fL -s -S \
|
||||
https://raw.githubusercontent.com/tphakala/birdnet-go/refs/heads/main/internal/conf/config.yaml \
|
||||
-o "$CONFIG_LOCATION"; then
|
||||
bashio::log.warning "Could not download default config.yaml; seeding an empty document so addon defaults can populate it"
|
||||
echo '{}' > "$CONFIG_LOCATION"
|
||||
fi
|
||||
fi
|
||||
|
||||
#################
|
||||
# Migrate Database
|
||||
#################
|
||||
if [ -f /data/birdnet.db ]; then
|
||||
bashio::log.warning "Moving birdnet.db to /config/birdnet.db"
|
||||
mv /data/birdnet.db /config
|
||||
fi
|
||||
|
||||
######################
|
||||
# Birdsongs Location
|
||||
######################
|
||||
# Read the current folder from config.yaml; "// """ collapses both missing
|
||||
# keys and explicit nulls (e.g. in a freshly seeded "{}" doc) to an empty
|
||||
# string so the ${VAR:-DEFAULT} fallback below kicks in.
|
||||
CURRENT_BIRDSONGS_FOLDER="$(yq -r '.realtime.audio.export.path // ""' "$CONFIG_LOCATION")"
|
||||
CURRENT_BIRDSONGS_FOLDER="${CURRENT_BIRDSONGS_FOLDER:-$DEFAULT_BIRDSONGS_FOLDER}"
|
||||
# Treat the upstream-shipped relative "clips/" as the legacy default.
|
||||
if [[ "$CURRENT_BIRDSONGS_FOLDER" == "clips" || "$CURRENT_BIRDSONGS_FOLDER" == "clips/" ]]; then
|
||||
CURRENT_BIRDSONGS_FOLDER="$DEFAULT_BIRDSONGS_FOLDER"
|
||||
fi
|
||||
CURRENT_BIRDSONGS_FOLDER="$(normalize_path "$CURRENT_BIRDSONGS_FOLDER")"
|
||||
|
||||
# Set the new birdsongs folder from addon options (default: relative "clips").
|
||||
BIRDSONGS_FOLDER="$(bashio::config "BIRDSONGS_FOLDER")"
|
||||
BIRDSONGS_FOLDER="$(normalize_path "${BIRDSONGS_FOLDER:-clips}")"
|
||||
|
||||
validate_safe_path "$BIRDSONGS_FOLDER"
|
||||
validate_safe_path "$CURRENT_BIRDSONGS_FOLDER"
|
||||
|
||||
if [[ ! "$BIRDSONGS_FOLDER" == /* ]]; then
|
||||
if [ ! -d "/config/$BIRDSONGS_FOLDER" ]; then
|
||||
mkdir -p "/config/$BIRDSONGS_FOLDER"
|
||||
fi
|
||||
if [ -d "/data/$BIRDSONGS_FOLDER" ]; then
|
||||
if [ -n "$(ls -A /data/"$BIRDSONGS_FOLDER" 2> /dev/null)" ]; then
|
||||
cp -rf /data/"$BIRDSONGS_FOLDER"/* "/config/$BIRDSONGS_FOLDER"/
|
||||
fi
|
||||
rm -r "/data/$BIRDSONGS_FOLDER"
|
||||
fi
|
||||
ln -sf "/config/$BIRDSONGS_FOLDER" "/data/$BIRDSONGS_FOLDER"
|
||||
fi
|
||||
|
||||
bashio::log.info "... audio clips saved to $BIRDSONGS_FOLDER according to addon options"
|
||||
|
||||
# Migrate data if the folder has changed
|
||||
if [[ "$CURRENT_BIRDSONGS_FOLDER" != "$BIRDSONGS_FOLDER" ]]; then
|
||||
bashio::log.warning "Birdsongs folder changed from $CURRENT_BIRDSONGS_FOLDER to $BIRDSONGS_FOLDER"
|
||||
# Update config.yaml with the new birdsongs folder path (trailing slash
|
||||
# restored only at the boundary, since birdnet-go expects it).
|
||||
yq -i -y ".realtime.audio.export.path = \"${BIRDSONGS_FOLDER}/\"" "$CONFIG_LOCATION"
|
||||
# Move files only if sqlite paths changed
|
||||
if [[ -d "$CURRENT_BIRDSONGS_FOLDER" && "$(ls -A "$CURRENT_BIRDSONGS_FOLDER")" ]]; then
|
||||
bashio::log.warning "Migrating files from $CURRENT_BIRDSONGS_FOLDER to $BIRDSONGS_FOLDER"
|
||||
# The absolute-path target (e.g. the default /config/clips) is never
|
||||
# created by the relative-path block above, so ensure it exists before
|
||||
# copying into it; otherwise cp aborts the init script under set -e.
|
||||
mkdir -p "$BIRDSONGS_FOLDER"
|
||||
cp -rnf "$CURRENT_BIRDSONGS_FOLDER"/* "$BIRDSONGS_FOLDER"/
|
||||
mv "$CURRENT_BIRDSONGS_FOLDER" "${CURRENT_BIRDSONGS_FOLDER}_migrated"
|
||||
fi
|
||||
# Adapt the database
|
||||
if [ -f /config/birdnet.db ]; then
|
||||
backup="$(date +%Y%m%d_%H%M%S)"
|
||||
BACKUP_FILE="/config/birdnet.db_${backup}"
|
||||
bashio::log.warning "Modifying database paths from $CURRENT_BIRDSONGS_FOLDER to $BIRDSONGS_FOLDER. A backup will be created at ${BACKUP_FILE}"
|
||||
|
||||
# Create backup at the absolute path we'll restore from on failure.
|
||||
if ! cp /config/birdnet.db "$BACKUP_FILE"; then
|
||||
bashio::log.error "Failed to create a backup of the database. Aborting path modification."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Paths were validated above against [A-Za-z0-9._/-]+ so quote
|
||||
# escaping in the SQL literal is not a concern.
|
||||
SQL_QUERY="UPDATE notes SET clip_name = '${BIRDSONGS_FOLDER}/' || substr(clip_name, length('${CURRENT_BIRDSONGS_FOLDER}/') + 1) WHERE clip_name LIKE '${CURRENT_BIRDSONGS_FOLDER}/%';"
|
||||
|
||||
if ! sqlite3 /config/birdnet.db "$SQL_QUERY"; then
|
||||
bashio::log.warning "An error occurred while updating the paths. The database backup will be restored."
|
||||
if [ -f "$BACKUP_FILE" ]; then
|
||||
mv "$BACKUP_FILE" /config/birdnet.db
|
||||
bashio::log.info "The database backup has been restored."
|
||||
else
|
||||
bashio::log.error "Backup file $BACKUP_FILE not found! Manual intervention required."
|
||||
fi
|
||||
else
|
||||
bashio::log.info "Paths have been successfully updated."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
####################
|
||||
# Correct Defaults
|
||||
####################
|
||||
# Seed addon-specific defaults only if the user has not set them in
|
||||
# config.yaml. The "//=" form leaves any user-edited value alone, so
|
||||
# changes made via the BirdNET-Go UI or by hand-editing /config/config.yaml
|
||||
# survive container restarts.
|
||||
bashio::log.info "Seeding default configuration values (only if missing)"
|
||||
|
||||
# Upstream's shipped default config.yaml explicitly sets output.sqlite.path
|
||||
# to the relative "birdnet.db", so the "//=" below (default-if-missing)
|
||||
# never fires for it. A relative path resolves against the app's working
|
||||
# directory, which lives in the ephemeral container filesystem rather than
|
||||
# a persistent volume, so the database is silently recreated empty on every
|
||||
# restart. Rewrite any relative sqlite path to live under the persistent
|
||||
# /config so detections survive reboots.
|
||||
CURRENT_SQLITE_PATH="$(yq -r '.output.sqlite.path // ""' "$CONFIG_LOCATION")"
|
||||
if [[ -n "$CURRENT_SQLITE_PATH" && "$CURRENT_SQLITE_PATH" != /* ]]; then
|
||||
validate_safe_path "$CURRENT_SQLITE_PATH"
|
||||
NEW_SQLITE_PATH="/config/${CURRENT_SQLITE_PATH}"
|
||||
bashio::log.warning "output.sqlite.path ('$CURRENT_SQLITE_PATH') is relative and would not persist across restarts; rewriting to $NEW_SQLITE_PATH"
|
||||
# SQLite does not create missing parent directories, so ensure one exists
|
||||
# if the (validated, traversal-free) path includes a subdirectory.
|
||||
mkdir -p "$(dirname "$NEW_SQLITE_PATH")"
|
||||
yq -i -y ".output.sqlite.path = \"${NEW_SQLITE_PATH}\"" "$CONFIG_LOCATION"
|
||||
fi
|
||||
|
||||
yq -i -y '.output.sqlite.path //= "/config/birdnet.db"' "$CONFIG_LOCATION"
|
||||
|
||||
####################
|
||||
# Log Management
|
||||
####################
|
||||
LOG_MAX_SIZE_MB="$(bashio::config "LOG_MAX_SIZE_MB")"
|
||||
LOG_MAX_SIZE_MB="${LOG_MAX_SIZE_MB:-50}"
|
||||
LOG_MAX_AGE_DAYS="$(bashio::config "LOG_MAX_AGE_DAYS")"
|
||||
LOG_MAX_AGE_DAYS="${LOG_MAX_AGE_DAYS:-7}"
|
||||
|
||||
bashio::log.info "Seeding default log rotation: max ${LOG_MAX_SIZE_MB}MB per file, max ${LOG_MAX_AGE_DAYS} days retention (only applied if not already set)"
|
||||
|
||||
# Seed log-rotation defaults; do not clobber user-edited values.
|
||||
yq -i -y ".logging.file_output.max_size //= ${LOG_MAX_SIZE_MB}" "$CONFIG_LOCATION"
|
||||
yq -i -y ".logging.file_output.max_age //= ${LOG_MAX_AGE_DAYS}" "$CONFIG_LOCATION"
|
||||
yq -i -y '.logging.file_output.max_rotated_files //= 3' "$CONFIG_LOCATION"
|
||||
yq -i -y '.logging.file_output.compress //= true' "$CONFIG_LOCATION"
|
||||
|
||||
# Trim existing log files that exceed the configured max age
|
||||
LOG_DIR="/config/logs"
|
||||
if [ -d "$LOG_DIR" ]; then
|
||||
bashio::log.info "Trimming log files older than ${LOG_MAX_AGE_DAYS} days in ${LOG_DIR}"
|
||||
ln -sf "$LOG_DIR" /logs
|
||||
find "$LOG_DIR" -type f -name "*.log*" -mtime +"$LOG_MAX_AGE_DAYS" -delete 2>/dev/null || true
|
||||
fi
|
||||
18
birdnet-go-dev/rootfs/etc/cont-init.d/32-nginx_ingress.sh
Executable file
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
set -e
|
||||
|
||||
#################
|
||||
# NGINX SETTING #
|
||||
#################
|
||||
|
||||
declare ingress_interface
|
||||
declare ingress_port
|
||||
|
||||
echo "Adapting for ingress"
|
||||
ingress_port=$(bashio::addon.ingress_port)
|
||||
ingress_interface=$(bashio::addon.ip_address)
|
||||
ingress_entry=$(bashio::addon.ingress_entry)
|
||||
sed -i "s/%%port%%/${ingress_port}/g" /etc/nginx/servers/ingress.conf
|
||||
sed -i "s/%%interface%%/${ingress_interface}/g" /etc/nginx/servers/ingress.conf
|
||||
sed -i "s|%%ingress_entry%%|${ingress_entry}|g" /etc/nginx/servers/ingress.conf
|
||||
112
birdnet-go-dev/rootfs/etc/cont-init.d/33-mariadb.sh
Executable file
@@ -0,0 +1,112 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
set -e
|
||||
|
||||
# When the Home Assistant MariaDB addon is active, optionally wire its
|
||||
# credentials directly into BirdNET-Go's config.yaml. Upstream reads MySQL
|
||||
# settings only from YAML (no env-var overrides exist), so this is the only
|
||||
# way to auto-configure them. The behaviour is opt-in via the
|
||||
# mariadb_auto_config addon option.
|
||||
#
|
||||
# When the option is off but MariaDB is detected, we log a one-shot hint and
|
||||
# ensure config.yaml falls back to SQLite (reverting any previously written
|
||||
# mysql block). This is safe because BirdNET-Go's config.yaml defaults to
|
||||
# SQLite and the mysql block is only ever written by this script.
|
||||
#
|
||||
# When the option is on we:
|
||||
# 1. Create the "birdnet" database if it does not already exist — birdnet-go
|
||||
# connects to an existing schema and does not create it automatically.
|
||||
# 2. Write the MySQL credentials into config.yaml and disable SQLite.
|
||||
|
||||
CONFIG_LOCATION="/config/config.yaml"
|
||||
MYSQL_DATABASE="birdnet"
|
||||
|
||||
if ! bashio::services.available 'mysql'; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
MYSQL_HOST="$(bashio::services 'mysql' 'host')"
|
||||
MYSQL_PORT="$(bashio::services 'mysql' 'port')"
|
||||
MYSQL_USER="$(bashio::services 'mysql' 'username')"
|
||||
MYSQL_PASS="$(bashio::services 'mysql' 'password')"
|
||||
|
||||
if ! bashio::config.true 'mariadb_auto_config'; then
|
||||
bashio::log.green "---"
|
||||
bashio::log.yellow "Home Assistant MariaDB addon detected but mariadb_auto_config is disabled; ensuring BirdNET-Go uses SQLite."
|
||||
bashio::log.yellow "Set 'mariadb_auto_config: true' in the addon options to wire MariaDB into BirdNET-Go automatically. Connection details:"
|
||||
bashio::log.blue "Database user : ${MYSQL_USER}"
|
||||
bashio::log.blue "Database password: [redacted]"
|
||||
bashio::log.blue "Database name : ${MYSQL_DATABASE}"
|
||||
bashio::log.blue "Host-name : ${MYSQL_HOST}"
|
||||
bashio::log.blue "Port : ${MYSQL_PORT}"
|
||||
bashio::log.green "---"
|
||||
if [ -f "$CONFIG_LOCATION" ]; then
|
||||
# Only revert if config.yaml points at the HA MariaDB host we would have
|
||||
# written — a mysql block pointing at a different host was set manually.
|
||||
# shellcheck disable=SC2016
|
||||
CURRENT_MYSQL_HOST="$(yq -r '.output.mysql.host // empty' "$CONFIG_LOCATION" 2>/dev/null || true)"
|
||||
if yq -e '.output.mysql.enabled == true' "$CONFIG_LOCATION" >/dev/null 2>&1 \
|
||||
&& [ "${CURRENT_MYSQL_HOST}" = "${MYSQL_HOST}" ]; then
|
||||
yq -i -y \
|
||||
'.output.mysql.enabled = false
|
||||
| .output.sqlite.enabled = true' \
|
||||
"$CONFIG_LOCATION"
|
||||
fi
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ ! -f "$CONFIG_LOCATION" ]; then
|
||||
bashio::log.warning "Skipping MariaDB auto-configuration: $CONFIG_LOCATION not found"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
bashio::log.green "---"
|
||||
bashio::log.blue "mariadb_auto_config enabled; creating MariaDB database and wiring credentials into BirdNET-Go config"
|
||||
bashio::log.blue "Host: ${MYSQL_HOST}:${MYSQL_PORT}"
|
||||
bashio::log.blue "User: ${MYSQL_USER}"
|
||||
bashio::log.blue "Database: ${MYSQL_DATABASE}"
|
||||
bashio::log.green "---"
|
||||
|
||||
# Resolve MariaDB hostname to IPv4: on HAOS >=17.3 the Supervisor network
|
||||
# gained IPv6, but the MariaDB addon only grants its user from the IPv4
|
||||
# subnet. Fall back to the raw hostname if resolution fails.
|
||||
MYSQL_HOST_RESOLVED="$(getent ahostsv4 "${MYSQL_HOST}" 2>/dev/null | awk '{print $1; exit}')"
|
||||
MYSQL_HOST_RESOLVED="${MYSQL_HOST_RESOLVED:-${MYSQL_HOST}}"
|
||||
if [ "${MYSQL_HOST_RESOLVED}" != "${MYSQL_HOST}" ]; then
|
||||
bashio::log.blue "Resolved ${MYSQL_HOST} -> ${MYSQL_HOST_RESOLVED} (forcing IPv4)"
|
||||
fi
|
||||
|
||||
# Create the database — birdnet-go connects to an existing schema and does NOT
|
||||
# create it automatically. MYSQL_PWD avoids exposing the password via the
|
||||
# process command line.
|
||||
if ! MYSQL_PWD="${MYSQL_PASS}" mysql \
|
||||
--skip-ssl \
|
||||
--host="${MYSQL_HOST_RESOLVED}" \
|
||||
--port="${MYSQL_PORT}" \
|
||||
--user="${MYSQL_USER}" \
|
||||
--connect-timeout=10 \
|
||||
-e "CREATE DATABASE IF NOT EXISTS \`${MYSQL_DATABASE}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"; then
|
||||
bashio::log.error "Failed to create MariaDB database '${MYSQL_DATABASE}' — verify the MariaDB addon is running and the user has CREATE DATABASE privileges"
|
||||
exit 1
|
||||
fi
|
||||
bashio::log.blue "Database '${MYSQL_DATABASE}' is ready"
|
||||
|
||||
# Upstream config.go stores port as a string; pass it as such to match.
|
||||
# $host / $port / etc. are jq/yq variables, not shell expansions — the
|
||||
# single quotes around the filter are intentional.
|
||||
# shellcheck disable=SC2016
|
||||
yq -i -y \
|
||||
--arg host "$MYSQL_HOST" \
|
||||
--arg port "$MYSQL_PORT" \
|
||||
--arg user "$MYSQL_USER" \
|
||||
--arg pass "$MYSQL_PASS" \
|
||||
--arg db "$MYSQL_DATABASE" \
|
||||
'.output.mysql.enabled = true
|
||||
| .output.mysql.host = $host
|
||||
| .output.mysql.port = $port
|
||||
| .output.mysql.username = $user
|
||||
| .output.mysql.password = $pass
|
||||
| .output.mysql.database = $db
|
||||
| .output.sqlite.enabled = false' \
|
||||
"$CONFIG_LOCATION"
|
||||
77
birdnet-go-dev/rootfs/etc/cont-init.d/33-mqtt.sh
Executable file
@@ -0,0 +1,77 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
set -e
|
||||
|
||||
# When the Home Assistant MQTT addon is active, optionally wire its
|
||||
# credentials directly into BirdNET-Go's config.yaml. Upstream reads MQTT
|
||||
# settings only from YAML (no env-var overrides exist), so this is the only
|
||||
# way to auto-configure them. The behaviour is opt-in via the
|
||||
# mqtt_auto_config addon option. When the option is off but Mosquitto is
|
||||
# detected, we log a one-shot hint pointing users at the option.
|
||||
#
|
||||
# In addition to the broker credentials we enable BirdNET-Go's native Home
|
||||
# Assistant MQTT auto-discovery (realtime.mqtt.homeassistant.*). This makes
|
||||
# the detection sensors appear in Home Assistant automatically, so users no
|
||||
# longer have to hand-write the MQTT sensor YAML from HAINTEGRATION.md.
|
||||
|
||||
CONFIG_LOCATION="/config/config.yaml"
|
||||
|
||||
if ! bashio::services.available 'mqtt'; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
MQTT_HOST="$(bashio::services 'mqtt' 'host')"
|
||||
MQTT_PORT="$(bashio::services 'mqtt' 'port')"
|
||||
MQTT_USER="$(bashio::services 'mqtt' 'username')"
|
||||
MQTT_PASS="$(bashio::services 'mqtt' 'password')"
|
||||
MQTT_BROKER="tcp://${MQTT_HOST}:${MQTT_PORT}"
|
||||
|
||||
if ! bashio::config.true 'mqtt_auto_config'; then
|
||||
bashio::log.green "---"
|
||||
bashio::log.yellow "Home Assistant MQTT addon detected. Set 'mqtt_auto_config: true' in the addon options to wire it into BirdNET-Go automatically AND enable Home Assistant auto-discovery (sensors appear in HA with no manual YAML). Connection details:"
|
||||
bashio::log.blue "MQTT user : ${MQTT_USER}"
|
||||
bashio::log.blue "MQTT password: ${MQTT_PASS}"
|
||||
bashio::log.blue "MQTT broker : ${MQTT_BROKER}"
|
||||
bashio::log.green "---"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ ! -f "$CONFIG_LOCATION" ]; then
|
||||
bashio::log.warning "Skipping MQTT auto-configuration: $CONFIG_LOCATION not found"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
bashio::log.green "---"
|
||||
bashio::log.blue "mqtt_auto_config enabled; writing Home Assistant MQTT credentials into BirdNET-Go config"
|
||||
bashio::log.blue "Broker: ${MQTT_BROKER}"
|
||||
bashio::log.blue "User: ${MQTT_USER}"
|
||||
bashio::log.blue "Home Assistant auto-discovery: enabled (sensors appear in HA automatically)"
|
||||
bashio::log.green "---"
|
||||
|
||||
# $broker / $user / $pass / "birdnet" are jq/yq variables and literals,
|
||||
# not shell expansions, so the single quotes are intentional.
|
||||
#
|
||||
# Connection fields (enabled/broker/username/password) are force-set on every
|
||||
# start so they track the HA MQTT addon's rotating credentials. Topic and the
|
||||
# homeassistant.* discovery knobs use "//=" so they are only seeded when
|
||||
# missing. retain is seeded via an explicit has() check rather than "//=",
|
||||
# because jq treats a user-set "retain: false" as falsy and "//=" would wrongly
|
||||
# flip it back to true; has() seeds the default only when the key is truly
|
||||
# absent. Any value the user later changes in the BirdNET-Go UI or config.yaml
|
||||
# therefore survives restarts. homeassistant.enabled is force-set to true
|
||||
# because turning on discovery is the whole point of the auto-config option.
|
||||
# shellcheck disable=SC2016
|
||||
yq -i -y \
|
||||
--arg broker "$MQTT_BROKER" \
|
||||
--arg user "$MQTT_USER" \
|
||||
--arg pass "$MQTT_PASS" \
|
||||
'.realtime.mqtt.enabled = true
|
||||
| .realtime.mqtt.broker = $broker
|
||||
| .realtime.mqtt.username = $user
|
||||
| .realtime.mqtt.password = $pass
|
||||
| .realtime.mqtt.topic //= "birdnet"
|
||||
| (if (.realtime.mqtt | has("retain")) then . else .realtime.mqtt.retain = true end)
|
||||
| .realtime.mqtt.homeassistant.enabled = true
|
||||
| .realtime.mqtt.homeassistant.discovery_prefix //= "homeassistant"
|
||||
| .realtime.mqtt.homeassistant.device_name //= "BirdNET-Go"' \
|
||||
"$CONFIG_LOCATION"
|
||||
47
birdnet-go-dev/rootfs/etc/cont-init.d/99-run.sh
Executable file
@@ -0,0 +1,47 @@
|
||||
#!/command/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
set -e
|
||||
|
||||
#################
|
||||
# INITALISATION #
|
||||
#################
|
||||
|
||||
echo " "
|
||||
|
||||
# Allow advanced users to supply their own ALSA config (e.g. to enable JACK
|
||||
# or a custom dsnoop chain) by dropping asound.conf into the addon config
|
||||
# folder. Written to /root/.asoundrc because /etc/asound.conf is read-only.
|
||||
if [ -f /config/asound.conf ]; then
|
||||
if [ -r /config/asound.conf ]; then
|
||||
bashio::log.info "Using user-provided /config/asound.conf, overriding addon defaults"
|
||||
if ! cp /config/asound.conf /root/.asoundrc; then
|
||||
bashio::log.warning "Failed to copy /config/asound.conf; continuing with bundled /root/.asoundrc defaults"
|
||||
fi
|
||||
else
|
||||
bashio::log.warning "/config/asound.conf exists but is not readable; continuing with bundled /root/.asoundrc defaults"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check if alsa_card is provided
|
||||
CONFIG_LOCATION="/config/config.yaml"
|
||||
if bashio::config.true "homeassistant_microphone"; then
|
||||
bashio::log.info "homeassistant_microphone option is selected. The audio card config value is set to 'default'. Set in the addon options to which this is set"
|
||||
audio_card="default"
|
||||
yq -iy ".realtime.audio.source = \"${audio_card}\"" "$CONFIG_LOCATION"
|
||||
else
|
||||
bashio::log.info "homeassistant_microphone option is not set, keeping audio source configured via the UI"
|
||||
fi
|
||||
|
||||
########################
|
||||
# CONFIGURE birdnet-go #
|
||||
########################
|
||||
|
||||
bashio::log.info "Starting app..."
|
||||
# shellcheck disable=SC2086
|
||||
/usr/bin/entrypoint.sh birdnet-go realtime &
|
||||
true
|
||||
|
||||
# Wait for app to become available to start nginx
|
||||
bashio::net.wait_for 8080 localhost 900
|
||||
bashio::log.info "Starting NGinx..."
|
||||
exec nginx
|
||||
96
birdnet-go-dev/rootfs/etc/nginx/includes/mime.types
Normal file
@@ -0,0 +1,96 @@
|
||||
types {
|
||||
text/html html htm shtml;
|
||||
text/css css;
|
||||
text/xml xml;
|
||||
image/gif gif;
|
||||
image/jpeg jpeg jpg;
|
||||
application/javascript js;
|
||||
application/atom+xml atom;
|
||||
application/rss+xml rss;
|
||||
|
||||
text/mathml mml;
|
||||
text/plain txt;
|
||||
text/vnd.sun.j2me.app-descriptor jad;
|
||||
text/vnd.wap.wml wml;
|
||||
text/x-component htc;
|
||||
|
||||
image/png png;
|
||||
image/svg+xml svg svgz;
|
||||
image/tiff tif tiff;
|
||||
image/vnd.wap.wbmp wbmp;
|
||||
image/webp webp;
|
||||
image/x-icon ico;
|
||||
image/x-jng jng;
|
||||
image/x-ms-bmp bmp;
|
||||
|
||||
font/woff woff;
|
||||
font/woff2 woff2;
|
||||
|
||||
application/java-archive jar war ear;
|
||||
application/json json;
|
||||
application/mac-binhex40 hqx;
|
||||
application/msword doc;
|
||||
application/pdf pdf;
|
||||
application/postscript ps eps ai;
|
||||
application/rtf rtf;
|
||||
application/vnd.apple.mpegurl m3u8;
|
||||
application/vnd.google-earth.kml+xml kml;
|
||||
application/vnd.google-earth.kmz kmz;
|
||||
application/vnd.ms-excel xls;
|
||||
application/vnd.ms-fontobject eot;
|
||||
application/vnd.ms-powerpoint ppt;
|
||||
application/vnd.oasis.opendocument.graphics odg;
|
||||
application/vnd.oasis.opendocument.presentation odp;
|
||||
application/vnd.oasis.opendocument.spreadsheet ods;
|
||||
application/vnd.oasis.opendocument.text odt;
|
||||
application/vnd.openxmlformats-officedocument.presentationml.presentation
|
||||
pptx;
|
||||
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
|
||||
xlsx;
|
||||
application/vnd.openxmlformats-officedocument.wordprocessingml.document
|
||||
docx;
|
||||
application/vnd.wap.wmlc wmlc;
|
||||
application/x-7z-compressed 7z;
|
||||
application/x-cocoa cco;
|
||||
application/x-java-archive-diff jardiff;
|
||||
application/x-java-jnlp-file jnlp;
|
||||
application/x-makeself run;
|
||||
application/x-perl pl pm;
|
||||
application/x-pilot prc pdb;
|
||||
application/x-rar-compressed rar;
|
||||
application/x-redhat-package-manager rpm;
|
||||
application/x-sea sea;
|
||||
application/x-shockwave-flash swf;
|
||||
application/x-stuffit sit;
|
||||
application/x-tcl tcl tk;
|
||||
application/x-x509-ca-cert der pem crt;
|
||||
application/x-xpinstall xpi;
|
||||
application/xhtml+xml xhtml;
|
||||
application/xspf+xml xspf;
|
||||
application/zip zip;
|
||||
|
||||
application/octet-stream bin exe dll;
|
||||
application/octet-stream deb;
|
||||
application/octet-stream dmg;
|
||||
application/octet-stream iso img;
|
||||
application/octet-stream msi msp msm;
|
||||
|
||||
audio/midi mid midi kar;
|
||||
audio/mpeg mp3;
|
||||
audio/ogg ogg;
|
||||
audio/x-m4a m4a;
|
||||
audio/x-realaudio ra;
|
||||
|
||||
video/3gpp 3gpp 3gp;
|
||||
video/mp2t ts;
|
||||
video/mp4 mp4;
|
||||
video/mpeg mpeg mpg;
|
||||
video/quicktime mov;
|
||||
video/webm webm;
|
||||
video/x-flv flv;
|
||||
video/x-m4v m4v;
|
||||
video/x-mng mng;
|
||||
video/x-ms-asf asx asf;
|
||||
video/x-ms-wmv wmv;
|
||||
video/x-msvideo avi;
|
||||
}
|
||||
16
birdnet-go-dev/rootfs/etc/nginx/includes/proxy_params.conf
Normal file
@@ -0,0 +1,16 @@
|
||||
proxy_http_version 1.1;
|
||||
proxy_ignore_client_abort off;
|
||||
proxy_read_timeout 86400s;
|
||||
proxy_redirect off;
|
||||
proxy_send_timeout 86400s;
|
||||
proxy_max_temp_file_size 0;
|
||||
|
||||
proxy_hide_header X-Frame-Options;
|
||||
proxy_set_header Accept-Encoding "";
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-NginX-Proxy true;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
1
birdnet-go-dev/rootfs/etc/nginx/includes/resolver.conf
Normal file
@@ -0,0 +1 @@
|
||||
resolver 127.0.0.11 ipv6=off;
|
||||
@@ -0,0 +1,6 @@
|
||||
root /dev/null;
|
||||
server_name $hostname;
|
||||
|
||||
add_header X-Content-Type-Options nosniff;
|
||||
add_header X-XSS-Protection "1; mode=block";
|
||||
add_header X-Robots-Tag none;
|
||||
9
birdnet-go-dev/rootfs/etc/nginx/includes/ssl_params.conf
Normal file
@@ -0,0 +1,9 @@
|
||||
ssl_protocols TLSv1.2;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:DHE-RSA-AES256-SHA;
|
||||
ssl_ecdh_curve secp384r1;
|
||||
ssl_session_timeout 10m;
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
ssl_session_tickets off;
|
||||
ssl_stapling on;
|
||||
ssl_stapling_verify on;
|
||||
81
birdnet-go-dev/rootfs/etc/nginx/nginx.conf
Normal file
@@ -0,0 +1,81 @@
|
||||
|
||||
# Run nginx in foreground.
|
||||
daemon off;
|
||||
|
||||
# This is run inside Docker.
|
||||
user root;
|
||||
|
||||
# Pid storage location.
|
||||
pid /var/run/nginx.pid;
|
||||
|
||||
# Set number of worker processes.
|
||||
worker_processes auto;
|
||||
|
||||
# Enables the use of JIT for regular expressions to speed-up their processing.
|
||||
pcre_jit on;
|
||||
|
||||
# Write error log to Hass.io add-on log.
|
||||
error_log /proc/1/fd/1 error;
|
||||
|
||||
# Load allowed environment vars
|
||||
env HASSIO_TOKEN;
|
||||
|
||||
# Load dynamic modules.
|
||||
include /etc/nginx/modules/*.conf;
|
||||
|
||||
# Max num of simultaneous connections by a worker process.
|
||||
events {
|
||||
worker_connections 8192;
|
||||
}
|
||||
|
||||
http {
|
||||
include /etc/nginx/includes/mime.types;
|
||||
|
||||
# https://emby.media/community/index.php?/topic/93074-how-to-emby-with-nginx-with-windows-specific-tips-and-csp-options/
|
||||
server_names_hash_bucket_size 64;
|
||||
gzip_disable "msie6";
|
||||
gzip_comp_level 6;
|
||||
gzip_min_length 1100;
|
||||
gzip_buffers 16 8k;
|
||||
gzip_proxied any;
|
||||
gzip_types
|
||||
text/plain
|
||||
text/css
|
||||
text/js
|
||||
text/xml
|
||||
text/javascript
|
||||
application/javascript
|
||||
application/x-javascript
|
||||
application/json
|
||||
application/xml
|
||||
application/rss+xml
|
||||
image/svg+xml;
|
||||
proxy_connect_timeout 1h;
|
||||
|
||||
log_format hassio '[$time_local] $status '
|
||||
'$http_x_forwarded_for($remote_addr) '
|
||||
'$request ($http_user_agent)';
|
||||
|
||||
access_log /proc/1/fd/1 hassio;
|
||||
client_max_body_size 4G;
|
||||
default_type application/octet-stream;
|
||||
gzip on;
|
||||
keepalive_timeout 65;
|
||||
sendfile on;
|
||||
server_tokens off;
|
||||
tcp_nodelay on;
|
||||
tcp_nopush on;
|
||||
|
||||
map $time_iso8601 $today {
|
||||
default "";
|
||||
}
|
||||
|
||||
map $http_upgrade $connection_upgrade {
|
||||
default upgrade;
|
||||
'' close;
|
||||
}
|
||||
|
||||
include /etc/nginx/includes/resolver.conf;
|
||||
|
||||
include /etc/nginx/servers/*.conf;
|
||||
}
|
||||
54
birdnet-go-dev/rootfs/etc/nginx/servers/ingress.conf
Normal file
@@ -0,0 +1,54 @@
|
||||
server {
|
||||
listen %%interface%%:%%port%% default_server;
|
||||
include /etc/nginx/includes/server_params.conf;
|
||||
include /etc/nginx/includes/proxy_params.conf;
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:8080/;
|
||||
rewrite ^%%ingress_entry%%/?(.*)$ /$1 break;
|
||||
|
||||
# Disable buffering (required for SSE and sub_filter)
|
||||
proxy_buffering off;
|
||||
proxy_request_buffering off;
|
||||
proxy_cache off;
|
||||
|
||||
# WebSocket support
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# Tell BirdNET-Go its proxy prefix. Upstream honours X-Ingress-Path
|
||||
# in internal/api/server.go and rewrites HTML href/src/action
|
||||
# attributes itself, so we no longer duplicate that work here.
|
||||
proxy_set_header X-Ingress-Path %%ingress_entry%%;
|
||||
|
||||
# Prevent timeouts
|
||||
proxy_read_timeout 86400;
|
||||
proxy_send_timeout 86400;
|
||||
|
||||
# sub_filter setup: keep gzip off and the type filter wide so JS gets
|
||||
# touched too (the upstream HTML rewriter does not look inside JS).
|
||||
proxy_set_header Accept-Encoding "";
|
||||
sub_filter_once off;
|
||||
sub_filter_types *;
|
||||
|
||||
# JS string-literal rewrites — paths embedded in JS code are not
|
||||
# touched by upstream's HTML rewriter, so we patch them here.
|
||||
sub_filter EventSource('/ EventSource('%%ingress_entry%%/;
|
||||
sub_filter fetch('/ fetch('%%ingress_entry%%/;
|
||||
sub_filter `/api/v `%%ingress_entry%%/api/v;
|
||||
sub_filter "'/api/v" "'%%ingress_entry%%/api/v";
|
||||
sub_filter \"/api/v \"%%ingress_entry%%/api/v;
|
||||
sub_filter `/u `%%ingress_entry%%/u;
|
||||
sub_filter "'/u" "'%%ingress_entry%%/u";
|
||||
sub_filter \"/u \"%%ingress_entry%%/u;
|
||||
sub_filter `/asset `%%ingress_entry%%/asset;
|
||||
sub_filter "'/asset" "'%%ingress_entry%%/asset";
|
||||
sub_filter \"/asset \"%%ingress_entry%%/asset;
|
||||
sub_filter window.location.origin} window.location.origin}%%ingress_entry%%;
|
||||
}
|
||||
}
|
||||
35
birdnet-go-dev/rootfs/root/.asoundrc
Normal file
@@ -0,0 +1,35 @@
|
||||
# Home Assistant addon: birdnet-go
|
||||
#
|
||||
# Shipped at /root/.asoundrc because /etc/asound.conf is read-only in this
|
||||
# environment. ALSA loads ~/.asoundrc as an additive layer on top of the
|
||||
# system config, so the overrides below take effect for the birdnet-go process
|
||||
# (which runs as root, HOME=/root).
|
||||
#
|
||||
# Replace ALSA PCM plugins whose backends are not available in the addon
|
||||
# container (JACK server, OSS /dev/dsp) with type "null" and hide them from
|
||||
# snd_device_name_hint(). Without this, miniaudio's capture-device enumeration
|
||||
# probes every PCM hint at startup, triggering noisy errors like:
|
||||
# - "Cannot connect to server socket" / "jack server is not running" (libjack)
|
||||
# - "ALSA lib pcm_oss.c: Cannot open device /dev/dsp"
|
||||
# - "ALSA lib pcm_dsnoop.c: unable to open slave"
|
||||
# BirdNET-Go itself never opens these PCMs; only the enumeration probe does.
|
||||
|
||||
pcm.!jack {
|
||||
type null
|
||||
hint.show off
|
||||
}
|
||||
|
||||
pcm.!oss {
|
||||
type null
|
||||
hint.show off
|
||||
}
|
||||
|
||||
pcm.!dsp {
|
||||
type null
|
||||
hint.show off
|
||||
}
|
||||
|
||||
pcm.!dsnoop {
|
||||
type null
|
||||
hint.show off
|
||||
}
|
||||
BIN
birdnet-go-dev/stats.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
12
birdnet-go-dev/updater.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"github_beta": true,
|
||||
"github_exclude": "-4",
|
||||
"github_fulltag": true,
|
||||
"last_update": "2026-06-07",
|
||||
"paused": true,
|
||||
"repository": "alexbelgium/hassio-addons",
|
||||
"slug": "birdnet-go",
|
||||
"source": "github",
|
||||
"upstream_repo": "tphakala/birdnet-go",
|
||||
"upstream_version": "nightly-20260601"
|
||||
}
|
||||
@@ -1,3 +1,9 @@
|
||||
## nightly-20260615-3 (05-07-2026)
|
||||
- Harden the `output.sqlite.path` rewrite added for the persistence fix: reject paths containing `..` traversal segments (shared `validate_safe_path` check), and create the destination's parent directory under `/config` when the relative path includes a subdirectory (e.g. `db/birdnet.db`), since SQLite does not create missing parent directories itself.
|
||||
|
||||
## nightly-20260615-2 (05-07-2026)
|
||||
- Minor bugs fixed
|
||||
- Fix detections/database not persisting across restarts on a fresh install: upstream's default `config.yaml` ships `output.sqlite.path: birdnet.db` (relative) explicitly, so the missing-only (`//=`) seeding introduced previously never rewrote it to an absolute path. A relative path resolves against the app's ephemeral working directory, so the database was silently recreated empty on every restart. Any relative `output.sqlite.path` is now rewritten to live under the persistent `/config` on startup; values already set to an absolute path are left untouched. (https://github.com/tphakala/birdnet-go/discussions/3774)
|
||||
- MQTT auto-config now also enables BirdNET-Go's native Home Assistant MQTT auto-discovery: detection sensors appear in Home Assistant automatically with no manual YAML (existing UI/config.yaml edits are preserved)
|
||||
- MQTT auto-config seeds `realtime.mqtt.retain: true` (only when unset) so sensor states survive Home Assistant restarts
|
||||
- Added supervisor watchdog (tcp://[HOST]:[PORT:8080]) so the add-on is automatically restarted if BirdNET-Go stops responding
|
||||
|
||||
@@ -128,4 +128,4 @@ slug: birdnet-go
|
||||
udev: true
|
||||
url: https://github.com/alexbelgium/hassio-addons/tree/master/birdnet-go
|
||||
usb: true
|
||||
version: "nightly-20260615"
|
||||
version: "nightly-20260615-3"
|
||||
|
||||
@@ -17,12 +17,22 @@ normalize_path() {
|
||||
|
||||
# Reject paths containing characters that would break the SQL/YAML literals
|
||||
# we substitute into below. We deliberately allow only "safe" filename chars.
|
||||
# Also reject ".." path segments so a relative path can't traverse outside
|
||||
# the directory we prefix it with (e.g. "/config") when we rewrite it below.
|
||||
validate_safe_path() {
|
||||
local p="$1"
|
||||
if [[ ! "$p" =~ ^[A-Za-z0-9._/-]+$ ]]; then
|
||||
bashio::log.fatal "Refusing unsafe path: '$p' (only [A-Za-z0-9._/-] allowed)"
|
||||
exit 1
|
||||
fi
|
||||
local segment
|
||||
local IFS=/
|
||||
for segment in $p; do
|
||||
if [[ "$segment" == ".." ]]; then
|
||||
bashio::log.fatal "Refusing unsafe path: '$p' (path traversal '..' is not allowed)"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
if [ ! -f "$CONFIG_LOCATION" ]; then
|
||||
@@ -135,6 +145,24 @@ fi
|
||||
# survive container restarts.
|
||||
bashio::log.info "Seeding default configuration values (only if missing)"
|
||||
|
||||
# Upstream's shipped default config.yaml explicitly sets output.sqlite.path
|
||||
# to the relative "birdnet.db", so the "//=" below (default-if-missing)
|
||||
# never fires for it. A relative path resolves against the app's working
|
||||
# directory, which lives in the ephemeral container filesystem rather than
|
||||
# a persistent volume, so the database is silently recreated empty on every
|
||||
# restart. Rewrite any relative sqlite path to live under the persistent
|
||||
# /config so detections survive reboots.
|
||||
CURRENT_SQLITE_PATH="$(yq -r '.output.sqlite.path // ""' "$CONFIG_LOCATION")"
|
||||
if [[ -n "$CURRENT_SQLITE_PATH" && "$CURRENT_SQLITE_PATH" != /* ]]; then
|
||||
validate_safe_path "$CURRENT_SQLITE_PATH"
|
||||
NEW_SQLITE_PATH="/config/${CURRENT_SQLITE_PATH}"
|
||||
bashio::log.warning "output.sqlite.path ('$CURRENT_SQLITE_PATH') is relative and would not persist across restarts; rewriting to $NEW_SQLITE_PATH"
|
||||
# SQLite does not create missing parent directories, so ensure one exists
|
||||
# if the (validated, traversal-free) path includes a subdirectory.
|
||||
mkdir -p "$(dirname "$NEW_SQLITE_PATH")"
|
||||
yq -i -y ".output.sqlite.path = \"${NEW_SQLITE_PATH}\"" "$CONFIG_LOCATION"
|
||||
fi
|
||||
|
||||
yq -i -y '.output.sqlite.path //= "/config/birdnet.db"' "$CONFIG_LOCATION"
|
||||
|
||||
####################
|
||||
|
||||
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 1.8 KiB |
@@ -1,4 +1,11 @@
|
||||
|
||||
## 0.8.2.1 (2026-07-05)
|
||||
- Re-tag of 0.8.2-1 with no content change. Home Assistant compares add-on versions with semver semantics, where a `-N` suffix counts as a *pre-release* and sorts **below** the base version — so users already on 0.8.2 saw the 0.8.2-1 nginx fix as "Up-to-date" with the Update button disabled. Four-segment `0.8.2.1` sorts above both `0.8.2` and `0.8.2-1` (and below the next upstream `0.8.3`), so the update becomes installable everywhere.
|
||||
|
||||
## 0.8.2-1 (2026-07-04)
|
||||
- Fix nginx failing to start with `limit_req_zone "api_rl" already bound` (502 on every page, Suncuss/BirdNET-PiPy#59). Upstream 0.8.2 added http-level rate-limit zones, and the ingress config was generated as a full copy of nginx.conf — duplicating those declarations in the shared http context. `ingress.conf` is now built from the `server` block only, so http-level directives stay declared once.
|
||||
- Comment out the new upstream Content-Security-Policy header in ingress mode, matching the existing X-* security-header handling (ingress runs inside Home Assistant's authenticated frame; direct access keeps the full CSP).
|
||||
|
||||
## 0.8.2 (2026-07-04)
|
||||
- Update to latest version from Suncuss/BirdNET-PiPy (changelog : https://github.com/Suncuss/BirdNET-PiPy/releases)
|
||||
|
||||
|
||||
@@ -96,4 +96,4 @@ schema:
|
||||
ssl: bool?
|
||||
slug: birdnet-pipy
|
||||
url: https://github.com/alexbelgium/hassio-addons/tree/master/birdnet-pipy
|
||||
version: "0.8.2"
|
||||
version: "0.8.2.1"
|
||||
|
||||
@@ -24,11 +24,18 @@ if ! [[ "${ingress_port}" =~ ^[0-9]+$ ]] || [[ "${ingress_port}" -le 0 ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
cp /etc/nginx/servers/nginx.conf /etc/nginx/servers/ingress.conf
|
||||
# Build the ingress server from the server block ONLY. Both files in
|
||||
# servers/ are included into one http context, so http-level directives
|
||||
# (map, limit_req_zone, ...) must stay declared once, in nginx.conf — a
|
||||
# duplicated limit_req_zone is a fatal "already bound" error and nginx
|
||||
# never starts (502 on every page). Upstream keeps all http-level
|
||||
# directives above its single column-0 "server {".
|
||||
sed -n '/^server {/,$p' /etc/nginx/servers/nginx.conf > /etc/nginx/servers/ingress.conf
|
||||
sed -i \
|
||||
-e "s|listen 80;|listen ${ingress_interface}:${ingress_port} default_server;|g" \
|
||||
-e "/index index.html;/a\\ include /etc/nginx/includes/ingress_params.conf;" \
|
||||
-e 's|^[[:space:]]*add_header X|#&|g' \
|
||||
-e 's|^[[:space:]]*add_header Content-Security-Policy|#&|g' \
|
||||
/etc/nginx/servers/ingress.conf
|
||||
|
||||
sed -i "s#%%ingress_entry%%#${ingress_entry}#g" /etc/nginx/includes/ingress_params.conf
|
||||
|
||||
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 1.4 KiB |
53
claude_desktop/CHANGELOG.md
Normal file
@@ -0,0 +1,53 @@
|
||||
## 1.8 (08-07-2026)
|
||||
|
||||
- Expose the Headroom live savings dashboard on mapped port `8787` when `install_headroom` is enabled, while keeping the proxy local-only if the port mapping is disabled.
|
||||
- Map `8787/tcp` by default and document the dashboard URL.
|
||||
|
||||
## 1.7 (07-07-2026)
|
||||
|
||||
- Add an hourly rtk + headroom token-savings report to the add-on log (`claude-gains-report.sh`, seeded via `/defaults/crontabs/root` and run by the base image's cron). Lets you confirm at a glance that both tools keep running and see accumulated gains — if the numbers stop growing, the tool has stopped working.
|
||||
- Run the Headroom optimization proxy as a supervised local backend (`svc-headroom` on 127.0.0.1:8787) so the `headroom_compress`/`headroom_retrieve` MCP tools can actually store/retrieve compressed content and record savings. It is a **backend only** — no client's `ANTHROPIC_BASE_URL` is routed through it, so the Claude Desktop app (which force-overrides it, [headroom #869](https://github.com/headroomlabs-ai/headroom/issues/869)) is unaffected. Previously the MCP server was registered but had no backend, so it recorded no savings.
|
||||
- Nudge Claude to use the headroom compression tools via a managed, idempotent block appended to the user's `CLAUDE.md` (removed automatically when `install_headroom` is disabled).
|
||||
|
||||
## 1.6 (07-07-2026)
|
||||
|
||||
- Fix default desktop launch failing when `install_headroom` is enabled (the default): the code rewrote the launch to `headroom wrap claude-desktop …`, but `headroom wrap` only supports coding-agent CLIs (`claude`, `codex`, ...) with arguments after `--`, so it produced an invalid command that left the app unlaunched. Leave the plain launch intact and instead register the `headroom` MCP server (`headroom mcp serve`) in Claude Desktop's config, exposing the `headroom_compress`/`headroom_retrieve`/`headroom_stats` tools inside the app. This is the supported headroom integration for Desktop, which overrides `ANTHROPIC_BASE_URL` so transparent proxy compression is not possible ([headroom #869](https://github.com/headroomlabs-ai/headroom/issues/869)). Disabling the option removes the entry again.
|
||||
- Make the autostart resilient: if the launch command fails to start, fall back to the plain Claude Desktop launch so the app always comes up.
|
||||
|
||||
## 1.5 (07-07-2026)
|
||||
|
||||
- Change the default Claude Desktop data location to `/data/data`.
|
||||
- Add Home Assistant smart context, Home Assistant MCP, and dangerous permission skip options.
|
||||
|
||||
## 1.4 (07-07-2026)
|
||||
|
||||
- Persist Claude Desktop sign-in: bundle gnome-keyring/libsecret/dbus-x11 and start an unlocked Secret Service in the desktop session, and launch with --password-store=gnome-libsecret. Fixes "Your sign-in won't be saved on this device. Install and unlock a system keyring". The keyring DB lives on persistent storage (/config/data), so the session survives restarts.
|
||||
|
||||
## 1.3 (07-07-2026)
|
||||
|
||||
- Fix startup crash loop ("All subprocesses terminated. Exiting."):
|
||||
- Make the Selkies desktop init oneshots (init-video, init-selkies-config) tolerant so a partially-permitted device/permission op in the HA sandbox no longer fails add-on bringup.
|
||||
- Pre-create /tmp/selkies_js.log so the base image's "chmod 777 /tmp/selkies*" calls never fail on an empty glob.
|
||||
- Reconcile XDG_RUNTIME_DIR to the tmpfs runtime dir instead of persistent storage.
|
||||
- Run Claude Desktop with --disable-dev-shm-usage and drop the misplaced shm_size env var (Home Assistant ignores shm_size), fixing Electron renderer crashes on the default 64 MB /dev/shm.
|
||||
|
||||
## 1.2 (07-07-2026)
|
||||
- Add baked-in git/GitHub CLI support with optional startup credential configuration.
|
||||
|
||||
- Fix Selkies startup by creating the s6 environment directory and XDG runtime directory before services start.
|
||||
|
||||
## 1.0 (07-07-2026)
|
||||
- Minor bugs fixed
|
||||
# Changelog
|
||||
|
||||
## 1.1
|
||||
|
||||
- Fix build failure: set HOME=/root when running rtk install script to ensure binary is installed to /root/.local/bin instead of /config/.local/bin (caused by LSIO base image overriding HOME)
|
||||
|
||||
## 1.0
|
||||
|
||||
- Fix build failure: remove separate `npm` apt package (already bundled in NodeSource nodejs)
|
||||
|
||||
## debianbookworm-1ae1f8ff-ls13
|
||||
|
||||
- Initial Claude Desktop add-on using LinuxServer Selkies, Home Assistant ingress, persistent sign-in data, runtime Claude Desktop updates, optional apt/pip additions, custom scripts, and bundled Claude Code optimization tools.
|
||||
142
claude_desktop/Dockerfile
Normal file
@@ -0,0 +1,142 @@
|
||||
#============================#
|
||||
# ALEXBELGIUM'S DOCKERFILE #
|
||||
#============================#
|
||||
#=== Home Assistant Addon ===#
|
||||
|
||||
#################
|
||||
# 1 Build Image #
|
||||
#################
|
||||
|
||||
ARG BUILD_FROM
|
||||
ARG BUILD_VERSION
|
||||
FROM ${BUILD_FROM}
|
||||
|
||||
##################
|
||||
# 2 Modify Image #
|
||||
##################
|
||||
|
||||
# Set S6 wait time
|
||||
ENV S6_CMD_WAIT_FOR_SERVICES=1 \
|
||||
S6_CMD_WAIT_FOR_SERVICES_MAXTIME=0 \
|
||||
S6_SERVICES_GRACETIME=0
|
||||
|
||||
USER root
|
||||
|
||||
# load volume
|
||||
VOLUME [ "/sys/fs/cgroup" ]
|
||||
|
||||
# Set shell
|
||||
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
||||
|
||||
# Allow UID and GID setting
|
||||
# hadolint ignore=SC2015,DL4006,SC2013,SC2086
|
||||
RUN \
|
||||
usermod --home /data/data abc && \
|
||||
if [[ -d /etc/services.d ]] && ls /etc/services.d/*/run 1> /dev/null 2>&1; then sed -i "1a set +e" /etc/services.d/*/run; fi
|
||||
|
||||
# Global LSIO modifications
|
||||
COPY ha_lsio.sh /ha_lsio.sh
|
||||
ARG CONFIGLOCATION="/data/data"
|
||||
RUN chmod 744 /ha_lsio.sh && if grep -qr "lsio" /etc; then /ha_lsio.sh "$CONFIGLOCATION"; fi && rm /ha_lsio.sh
|
||||
|
||||
##################
|
||||
# 3 Install apps #
|
||||
##################
|
||||
|
||||
# Add rootfs
|
||||
COPY rootfs/ /
|
||||
RUN find . -type f \( -name "*.sh" -o -name "run" -o -name "finish" \) -print -exec chmod +x {} \;
|
||||
|
||||
# Uses /bin for compatibility purposes
|
||||
# hadolint ignore=DL4005
|
||||
RUN if [ ! -f /bin/sh ] && [ -f /usr/bin/sh ]; then ln -s /usr/bin/sh /bin/sh; fi && \
|
||||
if [ ! -f /bin/bash ] && [ -f /usr/bin/bash ]; then ln -s /usr/bin/bash /bin/bash; fi
|
||||
|
||||
# Install Claude Desktop and Python tooling
|
||||
RUN curl -fsSLo /usr/share/keyrings/claude-desktop-archive-keyring.asc https://downloads.claude.ai/claude-desktop/key.asc && \
|
||||
echo "deb [arch=amd64,arm64 signed-by=/usr/share/keyrings/claude-desktop-archive-keyring.asc] https://downloads.claude.ai/claude-desktop/apt/stable stable main" > /etc/apt/sources.list.d/claude-desktop.list && \
|
||||
apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
claude-desktop \
|
||||
python3-pip \
|
||||
libsecret-1-0 \
|
||||
dbus-x11 \
|
||||
git gh && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install token-optimization tool prerequisites and binaries at build time
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends nodejs && \
|
||||
pip3 install --break-system-packages "headroom-ai[all]" && \
|
||||
curl -fsSL https://raw.githubusercontent.com/rtk-ai/rtk/refs/heads/master/install.sh -o /tmp/rtk-install.sh && \
|
||||
HOME=/root sh /tmp/rtk-install.sh && \
|
||||
rm /tmp/rtk-install.sh && \
|
||||
if [ -x /root/.local/bin/rtk ] && [ ! -x /usr/local/bin/rtk ]; then mv /root/.local/bin/rtk /usr/local/bin/rtk; fi && \
|
||||
if [ -x /usr/local/bin/rtk ]; then chmod +x /usr/local/bin/rtk; else echo "rtk binary was not installed on PATH"; exit 1; fi && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/* /root/.cache
|
||||
|
||||
# Modules
|
||||
ARG MODULES="00-banner.sh 00-global_var.sh 01-custom_script.sh 00-local_mounts.sh 00-smb_mounts.sh 90-dns_set.sh"
|
||||
|
||||
# Automatic modules download
|
||||
COPY ha_automodules.sh /ha_automodules.sh
|
||||
RUN chmod 744 /ha_automodules.sh && /ha_automodules.sh "$MODULES" && rm /ha_automodules.sh
|
||||
|
||||
# Manual apps
|
||||
ENV PACKAGES="nginx"
|
||||
|
||||
# Automatic apps & bashio
|
||||
COPY ha_autoapps.sh /ha_autoapps.sh
|
||||
RUN chmod 744 /ha_autoapps.sh && /ha_autoapps.sh "$PACKAGES" && rm /ha_autoapps.sh
|
||||
|
||||
################
|
||||
# 4 Entrypoint #
|
||||
################
|
||||
|
||||
# Add entrypoint
|
||||
COPY ha_entrypoint.sh /ha_entrypoint.sh
|
||||
RUN chmod 777 /ha_entrypoint.sh
|
||||
|
||||
# Install bashio
|
||||
COPY bashio-standalone.sh /usr/local/lib/bashio-standalone.sh
|
||||
RUN chmod 0755 /usr/local/lib/bashio-standalone.sh
|
||||
|
||||
ENTRYPOINT [ "/usr/bin/env" ]
|
||||
CMD [ "/ha_entrypoint.sh" ]
|
||||
|
||||
############
|
||||
# 5 Labels #
|
||||
############
|
||||
|
||||
ARG BUILD_ARCH
|
||||
ARG BUILD_DATE
|
||||
ARG BUILD_DESCRIPTION
|
||||
ARG BUILD_NAME
|
||||
ARG BUILD_REF
|
||||
ARG BUILD_REPOSITORY
|
||||
ARG BUILD_VERSION
|
||||
ENV BUILD_VERSION="${BUILD_VERSION}"
|
||||
LABEL \
|
||||
io.hass.name="${BUILD_NAME}" \
|
||||
io.hass.description="${BUILD_DESCRIPTION}" \
|
||||
io.hass.arch="${BUILD_ARCH}" \
|
||||
io.hass.type="addon" \
|
||||
io.hass.version=${BUILD_VERSION} \
|
||||
maintainer="alexbelgium (https://github.com/alexbelgium)" \
|
||||
org.opencontainers.image.title="${BUILD_NAME}" \
|
||||
org.opencontainers.image.description="${BUILD_DESCRIPTION}" \
|
||||
org.opencontainers.image.vendor="Home Assistant Add-ons" \
|
||||
org.opencontainers.image.authors="alexbelgium (https://github.com/alexbelgium)" \
|
||||
org.opencontainers.image.licenses="MIT" \
|
||||
org.opencontainers.image.url="https://github.com/alexbelgium" \
|
||||
org.opencontainers.image.source="https://github.com/${BUILD_REPOSITORY}" \
|
||||
org.opencontainers.image.documentation="https://github.com/${BUILD_REPOSITORY}/blob/main/README.md" \
|
||||
org.opencontainers.image.created=${BUILD_DATE} \
|
||||
org.opencontainers.image.revision=${BUILD_REF} \
|
||||
org.opencontainers.image.version=${BUILD_VERSION}
|
||||
|
||||
####################
|
||||
# 6 HealthcheckNOT #
|
||||
####################
|
||||
73
claude_desktop/README.md
Normal file
@@ -0,0 +1,73 @@
|
||||
# Home assistant add-on: Claude Desktop
|
||||
|
||||
![Supports aarch64 Architecture][aarch64-shield]
|
||||
![Supports amd64 Architecture][amd64-shield]
|
||||
![Project Maintenance][maintenance-shield]
|
||||
|
||||
Run the Claude Desktop Linux app inside a LinuxServer.io Selkies container and stream it through Home Assistant ingress.
|
||||
|
||||
## Installation
|
||||
|
||||
1. Add this repository to the Home Assistant add-on store.
|
||||
2. Install **Claude Desktop**.
|
||||
3. Start the add-on and open the web UI from the sidebar.
|
||||
4. Sign in with your Claude account from the Desktop app.
|
||||
|
||||
Claude Desktop sign-in requires a claude.ai plan that supports the Desktop app. API keys are not accepted by the Desktop application. Anthropic's Linux beta does not include Computer Use or dictation.
|
||||
|
||||
## Features
|
||||
|
||||
- Claude Desktop in single-app Selkies mode.
|
||||
- Home Assistant ingress support.
|
||||
- Persistent `$HOME` under `/data/data`, preserving Claude Desktop and Claude Code sign-in state across restarts.
|
||||
- Optional runtime Claude Desktop updates from Anthropic's apt repository.
|
||||
- Optional extra apt and pip package installation.
|
||||
- Baked-in `git` and GitHub CLI (`gh`) with optional startup credential configuration.
|
||||
- Custom script support through the repository standard `claude_desktop.sh` script.
|
||||
- Optional bundled Claude Code optimization tools: headroom, rtk, and caveman.
|
||||
- Headroom dashboard exposed on mapped port `8787` when `install_headroom` is enabled.
|
||||
- Low-power defaults: GPU device mapping, `AUTO_GPU=1`, `SELKIES_FRAMERATE=30`, `/tmp` tmpfs, and `$HOME/.cache` redirected to `/tmp/cache`.
|
||||
|
||||
## Options
|
||||
|
||||
| Option | Default | Description |
|
||||
| ------ | ------- | ----------- |
|
||||
| `PUID` / `PGID` | `0` / `0` | User and group used for persistent data ownership. |
|
||||
| `TZ` | | Optional timezone, for example `America/New_York`. |
|
||||
| `KEYBOARD` | | Optional Selkies keyboard layout. |
|
||||
| `PASSWORD` | | Optional password for direct Selkies ports. Set this before exposing ports `3000` or `3001`. |
|
||||
| `DRINODE` | | Optional GPU device override for Selkies. |
|
||||
| `DNS_server` | `8.8.8.8` | DNS server used by the standard DNS module. |
|
||||
| `auto_update` | `true` | Check Anthropic's apt repository and upgrade `claude-desktop` at add-on startup. |
|
||||
| `install_headroom` | `true` | Register the baked-in `headroom` MCP server in Claude Desktop, start the Headroom proxy backend, and expose the Headroom dashboard on mapped port `8787` at `/dashboard` when that port is open. This exposes the `headroom_compress`/`headroom_retrieve`/`headroom_stats` context-compression tools inside the app. (Claude Desktop overrides `ANTHROPIC_BASE_URL`, so transparent proxy compression is not possible — MCP is the supported path; see [headroom #869](https://github.com/headroomlabs-ai/headroom/issues/869).) Disabling removes the MCP entry and stops the backend/dashboard service. |
|
||||
| `install_rtk` | `true` | Configure the rtk Claude Code `PreToolUse` hook in the persistent Claude Code settings. |
|
||||
| `install_caveman` | `true` | Install the caveman Claude Code plugin into the persistent Claude Code home. |
|
||||
| `install_github_cli` | `true` | Enable first-start checks and setup for the baked-in `git` and `gh` commands. |
|
||||
| `github_token` | | Optional GitHub personal access token used to authenticate `gh` and configure Git credentials for GitHub. |
|
||||
| `github_username` | | Optional global Git author name. |
|
||||
| `github_email` | | Optional global Git author email. |
|
||||
| `ha_smart_context` | `true` | Enable Home Assistant smart context support for Claude tooling. |
|
||||
| `enable_ha_mcp` | `true` | Enable Home Assistant MCP support for Claude tooling. |
|
||||
| `dangerously_skip_permissions` | `false` | Expose Claude Code's dangerous permission skip mode option. Only enable if you understand the risk. |
|
||||
| `additional_apps` | | Comma-separated Debian apt packages to install at startup, for example `htop,git`. |
|
||||
| `additional_pip` | | Comma-separated pip packages to install at startup. Installs use `--break-system-packages`. |
|
||||
| `data_location` | `/data/data` | Persistent home directory location. Keep this persistent so Claude sign-in survives restarts. |
|
||||
| `networkdisks`, `cifsusername`, `cifspassword`, `cifsdomain` | | Standard SMB mount options. |
|
||||
| `localdisks` | | Standard local disk mount option. |
|
||||
| `env_vars` | `[]` | Extra environment variables to export into the container. This can override `SELKIES_*` defaults. |
|
||||
|
||||
## Custom scripts
|
||||
|
||||
The add-on includes the repository standard custom-script executor. On first start, it seeds a `claude_desktop.sh` file in the add-on config directory from the shared template. Commands in that script run during startup, allowing local customization without rebuilding the image.
|
||||
|
||||
## Data and cache locations
|
||||
|
||||
Persistent state is stored in the configured `data_location`. Claude Desktop stores sign-in data below `~/.config/Claude`, and Claude Code/tool configuration is stored below `~/.claude`. Volatile cache data is redirected to `/tmp/cache` through `$XDG_CACHE_HOME` and `$HOME/.cache`.
|
||||
|
||||
## Headroom dashboard
|
||||
|
||||
When `install_headroom` is enabled, the add-on starts the local Headroom proxy backend and maps port `8787` by default. Open `http://<home-assistant-host>:8787/dashboard` to view the Headroom live savings dashboard. If you disable the `8787/tcp` port mapping, the backend binds to localhost for MCP use only and the dashboard is not externally exposed.
|
||||
|
||||
[aarch64-shield]: https://img.shields.io/badge/aarch64-yes-green.svg
|
||||
[amd64-shield]: https://img.shields.io/badge/amd64-yes-green.svg
|
||||
[maintenance-shield]: https://img.shields.io/maintenance/yes/2026.svg
|
||||
118
claude_desktop/SIGN_IN.md
Normal file
@@ -0,0 +1,118 @@
|
||||
# Claude Desktop sign-in — shipped fixes and planned work
|
||||
|
||||
Two related sign-in problems when Claude Desktop runs inside the LinuxServer Selkies
|
||||
streamed desktop.
|
||||
|
||||
**Status:**
|
||||
- **Shipped:** Problem B (keyring persistence) is implemented in v1.4 (Dockerfile + `rootfs/defaults/autostart`).
|
||||
- **Planned only:** Problem A (in-desktop browser for OAuth) is intentionally not implemented.
|
||||
The image ships no browser; complete the login with the user-side workaround below.
|
||||
|
||||
---
|
||||
|
||||
## Problem A — Cannot complete login
|
||||
|
||||
Symptoms:
|
||||
- **"Continue with Google"** does nothing.
|
||||
- **"Continue with email"** sends a link that "must be opened from the same machine".
|
||||
|
||||
### Root cause
|
||||
Claude Desktop signs in through an **external web page** (Google OAuth or the email magic
|
||||
link) and then hands the token back to the app via the **`claude://` URL scheme**
|
||||
(auto-registered on first launch). Both paths need:
|
||||
1. a **web browser inside the streamed desktop** to render the auth page, and
|
||||
2. a **default-browser association** so the app's `xdg-open <url>` call goes somewhere.
|
||||
|
||||
The Selkies base image ships **no browser** and no default handler, so `xdg-open` has
|
||||
nothing to dispatch to → Google "does nothing", and the email link's final `claude://…`
|
||||
redirect only works on the machine running the app (the container), which currently can't
|
||||
render/handle it.
|
||||
|
||||
### Fix (image level)
|
||||
In `claude_desktop/Dockerfile`, install a browser and register defaults so the whole flow
|
||||
completes inside the session:
|
||||
- `apt-get install -y --no-install-recommends chromium` (Debian bookworm package name;
|
||||
`firefox-esr` is an alternative).
|
||||
- Set the default browser and confirm the scheme handlers, e.g. as an s6 oneshot or in the
|
||||
desktop `autostart` (runs as the session user with `$DISPLAY`/dbus available):
|
||||
```sh
|
||||
xdg-settings set default-web-browser chromium.desktop
|
||||
xdg-mime default claude-desktop.desktop x-scheme-handler/claude
|
||||
```
|
||||
- Verifying expectations (for reference, not a test step):
|
||||
`x-scheme-handler/https` → `chromium.desktop`, `x-scheme-handler/claude` →
|
||||
`claude-desktop.desktop`.
|
||||
|
||||
Then login is done entirely in the streamed desktop: **Continue with Google** opens
|
||||
Chromium in-session and the `claude://` redirect lands back in the app; or paste the email
|
||||
magic link into the in-session Chromium (not a phone).
|
||||
|
||||
### User-side workaround (no rebuild)
|
||||
- Add-on Configuration → `additional_apps: chromium`, restart (installed by
|
||||
`rootfs/etc/cont-init.d/80-configuration.sh`).
|
||||
- Run the two `xdg-settings`/`xdg-mime` commands once in an in-session terminal, or add them
|
||||
to the custom script `/addon_configs/db21ed7f_claude-desktop/claude-desktop.sh`.
|
||||
|
||||
---
|
||||
|
||||
## Problem B — "Your sign-in won't be saved on this device"
|
||||
|
||||
Symptom:
|
||||
> Install and unlock a system keyring (such as GNOME Keyring), then restart the app.
|
||||
|
||||
### Root cause
|
||||
Claude Desktop (Electron) persists its auth token with `safeStorage`, which on Linux
|
||||
encrypts via the **Secret Service API** (`org.freedesktop.secrets`) provided by
|
||||
gnome-keyring/kwallet. The Selkies base runs only a **system** D-Bus
|
||||
(`svc-dbus` → `dbus-daemon --system`) and has **no keyring daemon**, so `safeStorage` is
|
||||
unavailable and the token cannot be stored → the app warns and forgets the session on
|
||||
restart.
|
||||
|
||||
Note: the desktop itself already runs under a **session** bus —
|
||||
`root/defaults/startwm.sh` launches `dbus-launch --exit-with-session openbox-session`, so
|
||||
apps started from the openbox `autostart` inherit `DBUS_SESSION_BUS_ADDRESS`. The keyring
|
||||
must be started **inside that session** so it registers the secrets service on the same bus
|
||||
Claude Desktop uses. No extra `dbus-launch` is needed.
|
||||
|
||||
### Fix (image level)
|
||||
1. `claude_desktop/Dockerfile`: install
|
||||
`gnome-keyring libsecret-1-0 dbus-x11` (dbus-x11 provides `dbus-launch`, already used by
|
||||
startwm; libsecret-1-0 is the backend Electron dlopens).
|
||||
2. `claude_desktop/rootfs/defaults/autostart`: start & unlock an empty-password keyring
|
||||
before launching the app, and force the libsecret backend. Proposed content:
|
||||
```sh
|
||||
# Start + unlock a gnome-keyring secrets service so Claude Desktop can persist sign-in.
|
||||
# Runs inside the openbox session's dbus (startwm.sh: dbus-launch --exit-with-session).
|
||||
eval "$(printf '' | gnome-keyring-daemon --login)" 2>/dev/null || true
|
||||
eval "$(gnome-keyring-daemon --start --components=secrets)" 2>/dev/null || true
|
||||
dbus-update-activation-environment --all >/dev/null 2>&1 || true
|
||||
|
||||
claude-desktop --no-sandbox --disable-dev-shm-usage --password-store=gnome-libsecret
|
||||
```
|
||||
- `--login` reads the password from stdin (empty here), creating and unlocking the login
|
||||
keyring on first run and starting the daemon in login mode; `--start --components=secrets`
|
||||
then exposes the Secret Service and exports `GNOME_KEYRING_CONTROL`/`SSH_AUTH_SOCK`.
|
||||
- `--password-store=gnome-libsecret` forces Electron to use the libsecret backend instead
|
||||
of falling back to plaintext.
|
||||
3. Persistence: the keyring DB lives in `$HOME/.local/share/keyrings/` and `HOME=/config/data`
|
||||
(persistent add-on storage), so the empty-password login keyring survives restarts and is
|
||||
re-unlocked automatically each boot by the same `autostart` line — the sign-in then sticks.
|
||||
|
||||
### User-side workaround (no rebuild)
|
||||
- Add-on Configuration → `additional_apps: gnome-keyring, libsecret-1-0, dbus-x11`, restart.
|
||||
- Add the keyring-start lines above to the custom script
|
||||
`/addon_configs/db21ed7f_claude-desktop/claude-desktop.sh`, and relaunch Claude Desktop
|
||||
with `--password-store=gnome-libsecret` (e.g. edit the in-session openbox autostart).
|
||||
|
||||
---
|
||||
|
||||
## Files this plan would touch (when implemented)
|
||||
- `claude_desktop/Dockerfile` — install `chromium`, `gnome-keyring`, `libsecret-1-0`,
|
||||
`dbus-x11`; set default browser + scheme handlers.
|
||||
- `claude_desktop/rootfs/defaults/autostart` — keyring bootstrap + `--password-store` flag.
|
||||
- `claude_desktop/CHANGELOG.md` / `config.yaml` version bump.
|
||||
|
||||
## Open questions before implementing
|
||||
- Bundle **chromium** vs **firefox-esr** as the in-image browser?
|
||||
- Empty-password keyring (fully unattended) vs. reuse the add-on `PASSWORD` option to lock
|
||||
the keyring with the same password?
|
||||
72
claude_desktop/apparmor.txt
Normal file
@@ -0,0 +1,72 @@
|
||||
#include <tunables/global>
|
||||
|
||||
profile claude_desktop_addon flags=(attach_disconnected,mediate_deleted) {
|
||||
#include <abstractions/base>
|
||||
|
||||
capability chown,
|
||||
capability dac_override,
|
||||
capability dac_read_search,
|
||||
capability fowner,
|
||||
capability setgid,
|
||||
capability setuid,
|
||||
capability sys_chroot,
|
||||
capability sys_admin,
|
||||
file,
|
||||
signal,
|
||||
mount,
|
||||
umount,
|
||||
remount,
|
||||
network udp,
|
||||
network tcp,
|
||||
network dgram,
|
||||
network stream,
|
||||
network inet,
|
||||
network inet6,
|
||||
network netlink raw,
|
||||
network unix dgram,
|
||||
|
||||
|
||||
# S6-Overlay
|
||||
/init ix,
|
||||
/run/{s6,s6-rc*,service}/** ix,
|
||||
/package/** ix,
|
||||
/command/** ix,
|
||||
/run/{,**} rwk,
|
||||
/dev/tty rw,
|
||||
/bin/** ix,
|
||||
/usr/bin/** ix,
|
||||
/usr/lib/bashio/** ix,
|
||||
/etc/s6/** rix,
|
||||
/run/s6/** rix,
|
||||
/etc/services.d/** rwix,
|
||||
/etc/cont-init.d/** rwix,
|
||||
/etc/cont-finish.d/** rwix,
|
||||
/init rix,
|
||||
/var/run/** mrwkl,
|
||||
/var/run/ mrwkl,
|
||||
/dev/i2c-1 mrwkl,
|
||||
# Files required
|
||||
/dev/fuse mrwkl,
|
||||
/dev/sda1 mrwkl,
|
||||
/dev/sdb1 mrwkl,
|
||||
/dev/nvme0 mrwkl,
|
||||
/dev/nvme0n1 mrwkl,
|
||||
/dev/nvme1 mrwkl,
|
||||
/dev/mmcblk0p1 mrwkl,
|
||||
/dev/* mrwkl,
|
||||
/udev/* mrwkl,
|
||||
/tmp/** mrkwl,
|
||||
/dev/fuse/** mrkwl,
|
||||
/dev/** mrkwl,
|
||||
/sys/firmware/** mrkwl,
|
||||
|
||||
# Data access
|
||||
/data/** rw,
|
||||
|
||||
# suppress ptrace denials when using 'docker ps' or using 'ps' inside a container
|
||||
ptrace (trace,read) peer=docker-default,
|
||||
|
||||
# docker daemon confinement requires explict allow rule for signal
|
||||
signal (receive) set=(kill,term) peer=/usr/bin/docker,
|
||||
|
||||
}
|
||||
6
claude_desktop/build.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"build_from": {
|
||||
"aarch64": "ghcr.io/linuxserver/baseimage-selkies:arm64v8-debianbookworm",
|
||||
"amd64": "ghcr.io/linuxserver/baseimage-selkies:amd64-debianbookworm"
|
||||
}
|
||||
}
|
||||
94
claude_desktop/config.yaml
Normal file
@@ -0,0 +1,94 @@
|
||||
arch:
|
||||
- aarch64
|
||||
- amd64
|
||||
audio: true
|
||||
description: Claude Desktop streamed through a browser with LinuxServer Selkies
|
||||
devices:
|
||||
- /dev/dri
|
||||
- /dev/dri/card0
|
||||
- /dev/dri/card1
|
||||
- /dev/dri/renderD128
|
||||
- /dev/fuse
|
||||
environment:
|
||||
AUTO_GPU: "1"
|
||||
FM_HOME: /data/data
|
||||
HOME: /data/data
|
||||
PGID: "0"
|
||||
PUID: "0"
|
||||
SELKIES_FRAMERATE: "30"
|
||||
START_DOCKER: "false"
|
||||
TITLE: Claude Desktop
|
||||
image: ghcr.io/alexbelgium/claude_desktop-{arch}
|
||||
ingress: true
|
||||
init: false
|
||||
hassio_api: true
|
||||
hassio_role: manager
|
||||
homeassistant_api: true
|
||||
auth_api: true
|
||||
map:
|
||||
- addon_config:rw
|
||||
- share:rw
|
||||
- media:rw
|
||||
- ssl
|
||||
name: Claude Desktop
|
||||
options:
|
||||
env_vars: []
|
||||
DNS_server: 8.8.8.8
|
||||
data_location: /data/data
|
||||
PGID: 0
|
||||
PUID: 0
|
||||
additional_apps: ""
|
||||
additional_pip: ""
|
||||
auto_update: true
|
||||
github_email: ""
|
||||
ha_smart_context: true
|
||||
enable_ha_mcp: true
|
||||
dangerously_skip_permissions: false
|
||||
github_token: ""
|
||||
github_username: ""
|
||||
install_caveman: true
|
||||
install_github_cli: true
|
||||
install_headroom: true
|
||||
install_rtk: true
|
||||
panel_admin: false
|
||||
panel_icon: mdi:robot-happy
|
||||
ports:
|
||||
3001/tcp: null
|
||||
8787/tcp: 8787
|
||||
ports_description:
|
||||
3001/tcp: Web interface https
|
||||
8787/tcp: Headroom dashboard and proxy
|
||||
privileged:
|
||||
- SYS_ADMIN
|
||||
- DAC_READ_SEARCH
|
||||
schema:
|
||||
env_vars:
|
||||
- name: match(^[A-Za-z0-9_]+$)
|
||||
value: str?
|
||||
DNS_server: str?
|
||||
data_location: str?
|
||||
DRINODE: list(/dev/dri/card0|/dev/dri/card1|/dev/dri/card2|/dev/dri/renderD128|/dev/dri/renderD129|)?
|
||||
KEYBOARD: list(da-dk-qwerty|de-de-qwertz|en-gb-qwerty|en-us-qwerty|es-es-qwerty|fr-ch-qwertz|fr-fr-azerty|it-it-qwerty|ja-jp-qwerty|pt-br-qwerty|sv-se-qwerty|tr-tr-qwerty)?
|
||||
PASSWORD: str?
|
||||
PGID: int
|
||||
PUID: int
|
||||
TZ: match([A-Z][a-z]*./[A-Z][a-z]*.)?
|
||||
additional_apps: str?
|
||||
additional_pip: str?
|
||||
auto_update: bool?
|
||||
github_email: str?
|
||||
ha_smart_context: bool?
|
||||
enable_ha_mcp: bool?
|
||||
dangerously_skip_permissions: bool?
|
||||
github_token: password?
|
||||
github_username: str?
|
||||
install_caveman: bool
|
||||
install_github_cli: bool
|
||||
install_headroom: bool
|
||||
install_rtk: bool
|
||||
slug: claude_desktop
|
||||
tmpfs: true
|
||||
udev: true
|
||||
url: https://github.com/alexbelgium/hassio-addons
|
||||
version: "1.8"
|
||||
video: true
|
||||
BIN
claude_desktop/icon.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
claude_desktop/logo.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
34
claude_desktop/rootfs/defaults/autostart
Normal file
@@ -0,0 +1,34 @@
|
||||
#!/usr/bin/env sh
|
||||
# Persist Claude Desktop sign-in across restarts.
|
||||
# Claude Desktop (Electron) stores its auth token via safeStorage, which on Linux needs the
|
||||
# Secret Service API (org.freedesktop.secrets). Provide it with gnome-keyring on the openbox
|
||||
# session bus (startwm.sh runs `dbus-launch --exit-with-session`), unlocked with an empty
|
||||
# password so it comes back automatically after a restart. The keyring DB lives under
|
||||
# $HOME/.local/share/keyrings, and HOME=/data/data is persistent add-on storage, so the
|
||||
# saved sign-in survives add-on restarts.
|
||||
eval "$(gnome-keyring-daemon --start --components=secrets 2>/dev/null)" || true
|
||||
printf '' | gnome-keyring-daemon --unlock 2>/dev/null || true
|
||||
export GNOME_KEYRING_CONTROL SSH_AUTH_SOCK
|
||||
dbus-update-activation-environment --all >/dev/null 2>&1 || true
|
||||
|
||||
# --password-store=gnome-libsecret forces Electron onto the libsecret backend instead of
|
||||
# falling back to plaintext (and warning that the sign-in will not be saved).
|
||||
CLAUDE_DESKTOP_COMMAND_FILE="/tmp/claude-desktop-command"
|
||||
DEFAULT_CLAUDE_DESKTOP_COMMAND="claude-desktop --no-sandbox --disable-dev-shm-usage --password-store=gnome-libsecret"
|
||||
if [ -s "$CLAUDE_DESKTOP_COMMAND_FILE" ]; then
|
||||
CLAUDE_DESKTOP_COMMAND="$(cat "$CLAUDE_DESKTOP_COMMAND_FILE")"
|
||||
else
|
||||
CLAUDE_DESKTOP_COMMAND="$DEFAULT_CLAUDE_DESKTOP_COMMAND"
|
||||
fi
|
||||
if bashio::config.true 'install_headroom'; then
|
||||
export ANTHROPIC_BASE_URL="http://127.0.0.1:8787"
|
||||
fi
|
||||
|
||||
# Launch the configured command. If a custom/wrapped command fails to start, fall back to
|
||||
# the plain Claude Desktop launch so the desktop app still comes up for the user.
|
||||
if ! sh -c "$CLAUDE_DESKTOP_COMMAND"; then
|
||||
if [ "$CLAUDE_DESKTOP_COMMAND" != "$DEFAULT_CLAUDE_DESKTOP_COMMAND" ]; then
|
||||
echo "autostart: '$CLAUDE_DESKTOP_COMMAND' failed; falling back to default Claude Desktop launch" >&2
|
||||
exec sh -c "$DEFAULT_CLAUDE_DESKTOP_COMMAND"
|
||||
fi
|
||||
fi
|
||||
4
claude_desktop/rootfs/defaults/crontabs/root
Normal file
@@ -0,0 +1,4 @@
|
||||
# Hourly rtk + headroom token-savings report to the add-on log (heartbeat + gains).
|
||||
# Seeded to /data/data/crontabs/root by init-crontab-config and run by svc-cron; edit the
|
||||
# persistent copy to customize. Output goes to /proc/1/fd/1 so it shows in the add-on log.
|
||||
0 * * * * /usr/local/bin/claude-gains-report.sh > /proc/1/fd/1 2>&1
|
||||
107
claude_desktop/rootfs/etc/cont-init.d/20-folders.sh
Executable file
@@ -0,0 +1,107 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
# shellcheck disable=SC2046
|
||||
set -e
|
||||
|
||||
# Define user
|
||||
PUID=$(bashio::config "PUID")
|
||||
PGID=$(bashio::config "PGID")
|
||||
|
||||
# Check data location
|
||||
LOCATION="$(bashio::config 'data_location')"
|
||||
|
||||
if [[ "$LOCATION" = "null" || -z "$LOCATION" ]]; then
|
||||
LOCATION="/data/data"
|
||||
else
|
||||
LOCATIONOK=""
|
||||
for location in "/share" "/config" "/data" "/mnt"; do
|
||||
if [[ "$LOCATION" == "$location"* ]]; then
|
||||
LOCATIONOK=true
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -z "$LOCATIONOK" ]; then
|
||||
LOCATION="/data/data"
|
||||
bashio::log.fatal "Your data_location value can only be set in /share, /config, /data or /mnt. It will be reset to the default location : $LOCATION"
|
||||
fi
|
||||
fi
|
||||
|
||||
bashio::log.info "Setting data location to $LOCATION"
|
||||
|
||||
# LinuxServer Selkies services expect the s6 envdir at /run/s6/container_environment.
|
||||
# Home Assistant add-on startup can run without s6-overlay PID1, so create the envdir
|
||||
# ourselves before those services start and before scripts write required variables.
|
||||
S6_ENVDIR="/run/s6/container_environment"
|
||||
mkdir -p "$S6_ENVDIR"
|
||||
chmod 755 /run/s6 "$S6_ENVDIR"
|
||||
|
||||
XDG_RUNTIME_DIR="/run/user/$PUID"
|
||||
mkdir -p "$XDG_RUNTIME_DIR"
|
||||
chmod 700 "$XDG_RUNTIME_DIR"
|
||||
|
||||
for file in /etc/s6-overlay/s6-rc.d/*/run; do
|
||||
if [ "$(sed -n '1{/bash/p};q' "$file")" ] && ! grep -q '^export XDG_CACHE_HOME=/tmp/cache$' "$file"; then
|
||||
sed -i "1a export HOME=$LOCATION" "$file"
|
||||
sed -i "1a export FM_HOME=$LOCATION" "$file"
|
||||
sed -i "1a export XDG_CACHE_HOME=/tmp/cache" "$file"
|
||||
fi
|
||||
done
|
||||
|
||||
for folders in /defaults /etc/cont-init.d /etc/services.d /etc/s6-overlay/s6-rc.d; do
|
||||
if [ -d "$folders" ]; then
|
||||
find "$folders" -type f -exec sed -i "s|/data/data|$LOCATION|g" {} + &> /dev/null || true
|
||||
fi
|
||||
done
|
||||
|
||||
sed -i "s|^\(abc:[^:]*:[^:]*:[^:]*:[^:]*:\)[^:]*|\1$LOCATION|" /etc/passwd
|
||||
|
||||
printf "%s" "$LOCATION" > "$S6_ENVDIR/HOME"
|
||||
printf "%s" "$LOCATION" > "$S6_ENVDIR/FM_HOME"
|
||||
printf "%s" "/tmp/cache" > "$S6_ENVDIR/XDG_CACHE_HOME"
|
||||
printf "%s" "$XDG_RUNTIME_DIR" > "$S6_ENVDIR/XDG_RUNTIME_DIR"
|
||||
grep -qxF "export HOME=\"$LOCATION\"" ~/.bashrc 2>/dev/null || {
|
||||
printf "%s\n" "export HOME=\"$LOCATION\""
|
||||
printf "%s\n" "export FM_HOME=\"$LOCATION\""
|
||||
printf "%s\n" "export XDG_CACHE_HOME=\"/tmp/cache\""
|
||||
} >> ~/.bashrc
|
||||
|
||||
bashio::log.info "Creating $LOCATION"
|
||||
mkdir -p "$LOCATION" /tmp/cache "$XDG_RUNTIME_DIR"
|
||||
chmod 755 /tmp/cache
|
||||
chmod 700 "$XDG_RUNTIME_DIR"
|
||||
|
||||
# Pre-create the Selkies joystick log so the base image's "chmod 777 /tmp/selkies*"
|
||||
# calls (in init-selkies-config and svc-de) never fail on an empty glob.
|
||||
touch /tmp/selkies_js.log
|
||||
chmod 777 /tmp/selkies_js.log
|
||||
|
||||
if [ -e "$LOCATION/.cache" ] && [ ! -L "$LOCATION/.cache" ]; then
|
||||
rm -rf "$LOCATION/.cache"
|
||||
fi
|
||||
ln -sfn /tmp/cache "$LOCATION/.cache"
|
||||
|
||||
bashio::log.info "Setting ownership to $PUID:$PGID"
|
||||
chown -R "$PUID":"$PGID" "$LOCATION" /tmp/cache "$XDG_RUNTIME_DIR"
|
||||
chmod -R 700 "$LOCATION"
|
||||
|
||||
# The base init-selkies-config script overrides XDG_RUNTIME_DIR to $HOME/.XDG, which lands
|
||||
# on persistent storage and conflicts with the tmpfs runtime dir set above. Re-assert the
|
||||
# tmpfs value at the end of that oneshot so the app and desktop agree on one valid dir.
|
||||
SELKIES_CONFIG_RUN="/etc/s6-overlay/s6-rc.d/init-selkies-config/run"
|
||||
if [ -f "$SELKIES_CONFIG_RUN" ]; then
|
||||
sed -i '/^# XDG_RUNTIME_DIR override reconciled$/,+1d' "$SELKIES_CONFIG_RUN"
|
||||
printf '\n# XDG_RUNTIME_DIR override reconciled\nprintf "%%s" "%s" > /run/s6/container_environment/XDG_RUNTIME_DIR\n' "$XDG_RUNTIME_DIR" >> "$SELKIES_CONFIG_RUN"
|
||||
fi
|
||||
|
||||
# The Selkies desktop init oneshots do best-effort device/permission setup (mknod
|
||||
# /dev/input/*, chmod /tmp/selkies*, /dev/dri perms) that is only partially permitted in the
|
||||
# HA add-on sandbox. A non-zero exit from a oneshot fails add-on bringup and crash-loops the
|
||||
# container, so make these two tolerant and always report success. Longruns (svc-*) are left
|
||||
# untouched so s6 keeps supervising them with their real exit codes.
|
||||
for oneshot in init-video init-selkies-config; do
|
||||
run="/etc/s6-overlay/s6-rc.d/$oneshot/run"
|
||||
if [ -f "$run" ] && ! grep -q '^set +e$' "$run"; then
|
||||
sed -i "1a set +e" "$run"
|
||||
printf '\nexit 0\n' >> "$run"
|
||||
fi
|
||||
done
|
||||
54
claude_desktop/rootfs/etc/cont-init.d/80-configuration.sh
Executable file
@@ -0,0 +1,54 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
# shellcheck disable=SC2015
|
||||
set -e
|
||||
|
||||
if bashio::config.has_value 'additional_apps'; then
|
||||
bashio::log.info "Installing additional apps :"
|
||||
NEWAPPS=$(bashio::config 'additional_apps')
|
||||
if command -v "apt-get" &> /dev/null; then
|
||||
apt-get update -o Acquire::http::Timeout=10 -o Acquire::https::Timeout=10 &> /dev/null || bashio::log.warning "Unable to update apt package lists"
|
||||
fi
|
||||
for packagestoinstall in ${NEWAPPS//,/ }; do
|
||||
bashio::log.green "... $packagestoinstall"
|
||||
if command -v "apk" &> /dev/null; then
|
||||
apk add --no-cache "$packagestoinstall" &> /dev/null || (bashio::log.fatal "Error : $packagestoinstall not found")
|
||||
elif command -v "apt-get" &> /dev/null; then
|
||||
apt-get install -yqq --no-install-recommends "$packagestoinstall" &> /dev/null || (bashio::log.fatal "Error : $packagestoinstall not found")
|
||||
elif command -v "pacman" &> /dev/null; then
|
||||
pacman --noconfirm -S "$packagestoinstall" &> /dev/null || (bashio::log.fatal "Error : $packagestoinstall not found")
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if bashio::config.has_value 'additional_pip'; then
|
||||
for p in $(bashio::config 'additional_pip' | tr ',' ' '); do
|
||||
bashio::log.green "... pip: $p"
|
||||
pip3 install --break-system-packages "$p" || bashio::log.fatal "Error: pip package $p failed"
|
||||
done
|
||||
fi
|
||||
|
||||
if bashio::config.has_value 'TZ'; then
|
||||
TIMEZONE=$(bashio::config 'TZ')
|
||||
bashio::log.info "Setting timezone to $TIMEZONE"
|
||||
ln -snf /usr/share/zoneinfo/"$TIMEZONE" /etc/localtime
|
||||
echo "$TIMEZONE" > /etc/timezone
|
||||
fi || (bashio::log.fatal "Error : $TIMEZONE not found. Here is a list of valid timezones : https://manpages.ubuntu.com/manpages/focal/man3/DateTime::TimeZone::Catalog.3pm.html")
|
||||
|
||||
if bashio::config.has_value 'KEYBOARD'; then
|
||||
KEYBOARD=$(bashio::config 'KEYBOARD')
|
||||
bashio::log.info "Setting keyboard to $KEYBOARD"
|
||||
if [ -d /var/run/s6/container_environment ]; then printf "%s" "$KEYBOARD" > /var/run/s6/container_environment/KEYBOARD; fi
|
||||
grep -qxF "KEYBOARD=\"$KEYBOARD\"" ~/.bashrc 2>/dev/null || printf "%s\n" "KEYBOARD=\"$KEYBOARD\"" >> ~/.bashrc
|
||||
fi || true
|
||||
|
||||
if bashio::config.has_value 'PASSWORD'; then
|
||||
bashio::log.info "Setting password to the value defined in options"
|
||||
PASSWORD=$(bashio::config 'PASSWORD')
|
||||
passwd -d abc
|
||||
echo -e "$PASSWORD\n$PASSWORD" | passwd abc
|
||||
elif ! bashio::config.has_value 'PASSWORD' && { [[ -n "$(bashio::addon.port "3000")" ]] || [[ -n "$(bashio::addon.port "3001")" ]] }; then
|
||||
bashio::log.warning "SEVERE RISK IDENTIFIED"
|
||||
bashio::log.warning "You are opening an external port but your password is not defined"
|
||||
bashio::log.warning "You risk being hacked ! Please disable the external ports, or use a password"
|
||||
fi
|
||||
12
claude_desktop/rootfs/etc/cont-init.d/81-claude_update.sh
Executable file
@@ -0,0 +1,12 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
set -e
|
||||
|
||||
if bashio::config.true 'auto_update'; then
|
||||
bashio::log.info "Checking for Claude Desktop updates..."
|
||||
if apt-get update -o Acquire::http::Timeout=10 -o Acquire::https::Timeout=10 &> /dev/null && apt-get install -y --only-upgrade claude-desktop &> /dev/null; then
|
||||
bashio::log.info "Claude Desktop version: $(dpkg-query -W -f='${Version}' claude-desktop)"
|
||||
else
|
||||
bashio::log.warning "Update check failed (offline?), keeping current version"
|
||||
fi
|
||||
fi
|
||||
172
claude_desktop/rootfs/etc/cont-init.d/82-claude_tools.sh
Executable file
@@ -0,0 +1,172 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
set -e
|
||||
set -o pipefail
|
||||
mkdir -p "$HOME/.claude"
|
||||
|
||||
CLAUDE_DESKTOP_COMMAND_FILE="/tmp/claude-desktop-command"
|
||||
DEFAULT_CLAUDE_DESKTOP_COMMAND='claude-desktop --no-sandbox --disable-dev-shm-usage --password-store=gnome-libsecret'
|
||||
printf '%s\n' "$DEFAULT_CLAUDE_DESKTOP_COMMAND" > "$CLAUDE_DESKTOP_COMMAND_FILE"
|
||||
|
||||
# headroom's "wrap"/proxy routing works by setting ANTHROPIC_BASE_URL, which the Claude Desktop
|
||||
# Electron app force-overrides to the production endpoint (headroom #869), so transparent
|
||||
# compression cannot be applied to the desktop launch. The integration that does work with
|
||||
# Claude Desktop is headroom's MCP server, which exposes the headroom_compress/headroom_retrieve/
|
||||
# headroom_stats tools inside the app. Register it in Claude Desktop's MCP config, leaving the
|
||||
# plain launch untouched. The merge is idempotent and preserves any other MCP servers.
|
||||
CLAUDE_DESKTOP_CONFIG="$HOME/.config/Claude/claude_desktop_config.json"
|
||||
if bashio::config.true 'install_headroom'; then
|
||||
if command -v headroom &> /dev/null; then
|
||||
bashio::log.info "headroom $(headroom --version 2> /dev/null || true) available; registering the headroom MCP server for Claude Desktop"
|
||||
HEADROOM_BIN="$(command -v headroom)" CLAUDE_DESKTOP_CONFIG="$CLAUDE_DESKTOP_CONFIG" python3 - <<'PY' || bashio::log.warning "Unable to register the headroom MCP server automatically"
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
path = Path(os.environ["CLAUDE_DESKTOP_CONFIG"])
|
||||
try:
|
||||
data = json.loads(path.read_text()) if path.exists() else {}
|
||||
if not isinstance(data, dict):
|
||||
data = {}
|
||||
except Exception:
|
||||
if path.exists():
|
||||
path.rename(path.with_suffix(path.suffix + ".bak"))
|
||||
data = {}
|
||||
servers = data.get("mcpServers")
|
||||
if not isinstance(servers, dict):
|
||||
servers = {}
|
||||
data["mcpServers"] = servers
|
||||
servers["headroom"] = {"command": os.environ.get("HEADROOM_BIN", "headroom"), "args": ["mcp", "serve"]}
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(json.dumps(data, indent=2) + "\n")
|
||||
PY
|
||||
else
|
||||
bashio::log.warning "headroom is not available"
|
||||
fi
|
||||
elif [ -f "$CLAUDE_DESKTOP_CONFIG" ]; then
|
||||
bashio::log.info "Removing the headroom MCP server from Claude Desktop"
|
||||
CLAUDE_DESKTOP_CONFIG="$CLAUDE_DESKTOP_CONFIG" python3 - <<'PY' || bashio::log.warning "Unable to remove the headroom MCP server automatically"
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
path = Path(os.environ["CLAUDE_DESKTOP_CONFIG"])
|
||||
data = json.loads(path.read_text())
|
||||
if isinstance(data, dict):
|
||||
servers = data.get("mcpServers")
|
||||
if isinstance(servers, dict) and servers.pop("headroom", None) is not None:
|
||||
if not servers:
|
||||
data.pop("mcpServers", None)
|
||||
path.write_text(json.dumps(data, indent=2) + "\n")
|
||||
PY
|
||||
fi
|
||||
|
||||
# Guide Claude to actually use the headroom compression tools so the MCP integration produces
|
||||
# real savings (otherwise the tools sit unused and `headroom savings` stays empty). Managed,
|
||||
# idempotent block appended to the user's global CLAUDE.md; removed when headroom is disabled.
|
||||
CLAUDE_MD="$HOME/.claude/CLAUDE.md"
|
||||
HEADROOM_GUIDE_BEGIN="<!-- BEGIN headroom (managed by claude_desktop addon) -->"
|
||||
if bashio::config.true 'install_headroom'; then
|
||||
mkdir -p "$(dirname "$CLAUDE_MD")"
|
||||
if ! { [ -f "$CLAUDE_MD" ] && grep -qF "$HEADROOM_GUIDE_BEGIN" "$CLAUDE_MD"; }; then
|
||||
bashio::log.info "Adding headroom usage guidance to CLAUDE.md"
|
||||
{
|
||||
[ -s "$CLAUDE_MD" ] && printf '\n'
|
||||
cat <<'MD'
|
||||
<!-- BEGIN headroom (managed by claude_desktop addon) -->
|
||||
## Headroom context compression
|
||||
|
||||
A local Headroom proxy (127.0.0.1:8787) backs the `headroom` MCP tools. To save context tokens:
|
||||
when you produce or read a **large, structured** blob you will keep referring to — file listings,
|
||||
search results, JSON/config dumps, big command outputs, roughly >500 tokens — call
|
||||
`mcp__headroom__headroom_compress` on it and keep the returned compressed text + `hash` instead of
|
||||
the raw content. Call `mcp__headroom__headroom_retrieve` with that hash when you need the full
|
||||
original back. Skip compression for error/stack-trace output (Headroom deliberately protects it)
|
||||
and for small or one-off content. Use `mcp__headroom__headroom_stats` to check savings.
|
||||
<!-- END headroom (managed by claude_desktop addon) -->
|
||||
MD
|
||||
} >> "$CLAUDE_MD"
|
||||
fi
|
||||
elif [ -f "$CLAUDE_MD" ] && grep -qF "$HEADROOM_GUIDE_BEGIN" "$CLAUDE_MD"; then
|
||||
bashio::log.info "Removing headroom usage guidance from CLAUDE.md"
|
||||
CLAUDE_MD="$CLAUDE_MD" python3 - <<'PY' || bashio::log.warning "Unable to remove headroom guidance automatically"
|
||||
import os
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
path = Path(os.environ["CLAUDE_MD"])
|
||||
text = path.read_text()
|
||||
pattern = re.compile(
|
||||
r"\n*<!-- BEGIN headroom \(managed by claude_desktop addon\) -->.*?"
|
||||
r"<!-- END headroom \(managed by claude_desktop addon\) -->\n?",
|
||||
re.DOTALL,
|
||||
)
|
||||
new = pattern.sub("", text)
|
||||
if new != text:
|
||||
path.write_text(new)
|
||||
PY
|
||||
fi
|
||||
|
||||
if bashio::config.true 'install_rtk'; then
|
||||
if command -v rtk &> /dev/null; then
|
||||
if [ -f "$HOME/.claude/settings.json" ] && grep -q 'rtk hook claude' "$HOME/.claude/settings.json"; then
|
||||
bashio::log.info "rtk Claude Code hook already configured"
|
||||
else
|
||||
bashio::log.info "Configuring rtk Claude Code hook"
|
||||
RTK_NONINTERACTIVE=1 rtk init -g || bashio::log.warning "rtk global files configuration failed"
|
||||
python3 - <<'PY' || bashio::log.warning "Unable to configure rtk hook automatically"
|
||||
import json
|
||||
from pathlib import Path
|
||||
path = Path.home() / ".claude" / "settings.json"
|
||||
try:
|
||||
data = json.loads(path.read_text()) if path.exists() else {}
|
||||
if not isinstance(data, dict):
|
||||
data = {}
|
||||
except Exception:
|
||||
if path.exists():
|
||||
path.rename(path.with_suffix(path.suffix + ".bak"))
|
||||
data = {}
|
||||
hooks = data.setdefault("hooks", {})
|
||||
pre = hooks.setdefault("PreToolUse", [])
|
||||
rtk_entry = {"matcher": "Bash", "hooks": [{"type": "command", "command": "rtk hook claude"}]}
|
||||
if not any("rtk hook claude" in json.dumps(entry) for entry in pre if isinstance(entry, dict)):
|
||||
pre.append(rtk_entry)
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(json.dumps(data, indent=2) + "\n")
|
||||
PY
|
||||
fi
|
||||
else
|
||||
bashio::log.warning "rtk is not available"
|
||||
fi
|
||||
elif [ -f "$HOME/.claude/settings.json" ] && grep -q 'rtk' "$HOME/.claude/settings.json"; then
|
||||
bashio::log.info "Removing rtk Claude Code hook"
|
||||
python3 - <<'PY' || bashio::log.warning "Unable to remove rtk hook automatically"
|
||||
import json
|
||||
from pathlib import Path
|
||||
path = Path.home() / ".claude" / "settings.json"
|
||||
data = json.loads(path.read_text())
|
||||
hooks = data.get("hooks", {})
|
||||
for event, entries in list(hooks.items()):
|
||||
if isinstance(entries, list):
|
||||
hooks[event] = [entry for entry in entries if "rtk" not in json.dumps(entry)]
|
||||
if not hooks[event]:
|
||||
hooks.pop(event, None)
|
||||
if hooks:
|
||||
data["hooks"] = hooks
|
||||
else:
|
||||
data.pop("hooks", None)
|
||||
path.write_text(json.dumps(data, indent=2) + "\n")
|
||||
PY
|
||||
fi
|
||||
|
||||
if bashio::config.true 'install_caveman'; then
|
||||
if [ -d "$HOME/.claude/plugins/caveman" ] || find "$HOME/.claude" -maxdepth 4 -iname '*caveman*' -print -quit | grep -q .; then
|
||||
bashio::log.info "caveman Claude Code plugin already configured"
|
||||
else
|
||||
bashio::log.info "Installing caveman Claude Code plugin"
|
||||
curl --connect-timeout 10 --max-time 60 -fsSL https://raw.githubusercontent.com/JuliusBrussee/caveman/main/install.sh | bash >/dev/null || bashio::log.warning "caveman install failed (offline?)"
|
||||
fi
|
||||
else
|
||||
bashio::log.info "Disabling caveman Claude Code plugin"
|
||||
find "$HOME/.claude" -maxdepth 4 -iname '*caveman*' -exec rm -rf {} + 2> /dev/null || true
|
||||
fi
|
||||
41
claude_desktop/rootfs/etc/cont-init.d/83-github_cli.sh
Executable file
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
set -e
|
||||
set -o pipefail
|
||||
|
||||
if ! bashio::config.true 'install_github_cli'; then
|
||||
bashio::log.info "GitHub CLI setup disabled"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if ! command -v git > /dev/null 2>&1; then
|
||||
bashio::log.warning "git is not available"
|
||||
fi
|
||||
|
||||
if ! command -v gh > /dev/null 2>&1; then
|
||||
bashio::log.warning "gh is not available"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if bashio::config.has_value 'github_username'; then
|
||||
git config --global user.name "$(bashio::config 'github_username')"
|
||||
fi
|
||||
|
||||
if bashio::config.has_value 'github_email'; then
|
||||
git config --global user.email "$(bashio::config 'github_email')"
|
||||
fi
|
||||
|
||||
if bashio::config.has_value 'github_token'; then
|
||||
token="$(bashio::config 'github_token')"
|
||||
mkdir -p "$HOME/.config/gh"
|
||||
chmod 700 "$HOME/.config/gh"
|
||||
if env -u GH_TOKEN -u GITHUB_TOKEN gh auth status --hostname github.com > /dev/null 2>&1; then
|
||||
bashio::log.info "GitHub CLI already authenticated for github.com"
|
||||
else
|
||||
bashio::log.info "Configuring GitHub CLI authentication for github.com"
|
||||
printf '%s\n' "$token" | env -u GH_TOKEN -u GITHUB_TOKEN gh auth login --hostname github.com --with-token || bashio::log.warning "GitHub CLI authentication failed"
|
||||
fi
|
||||
env -u GH_TOKEN -u GITHUB_TOKEN gh auth setup-git --hostname github.com || bashio::log.warning "GitHub CLI git credential setup failed"
|
||||
else
|
||||
bashio::log.info "GitHub CLI available. Set github_token to authenticate gh and git operations."
|
||||
fi
|
||||
37
claude_desktop/rootfs/etc/cont-init.d/90-ingress.sh
Executable file
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
set -e
|
||||
|
||||
NGINX_CONFIG=/etc/nginx/sites-available/ingress.conf
|
||||
SUBFOLDER="$(bashio::addon.ingress_entry)"
|
||||
|
||||
# Ensure subfolder ends with a trailing slash (except for root)
|
||||
if [[ -n "${SUBFOLDER}" && "${SUBFOLDER}" != "/" ]]; then
|
||||
[[ "${SUBFOLDER}" == */ ]] || SUBFOLDER="${SUBFOLDER}/"
|
||||
else
|
||||
SUBFOLDER="/"
|
||||
fi
|
||||
|
||||
cp /defaults/default.conf "${NGINX_CONFIG}"
|
||||
|
||||
# Keep only the first (non-SSL) server block
|
||||
awk -v n=2 '/^[[:space:]]*server[[:space:]]*\{/{n--} n>0' "${NGINX_CONFIG}" > tmpfile
|
||||
mv tmpfile "${NGINX_CONFIG}"
|
||||
|
||||
# Disable IPv6 listeners for ingress proxying
|
||||
sed -i '/listen \[::\]/d' "${NGINX_CONFIG}"
|
||||
|
||||
# Adapt ports and upstream paths for Home Assistant ingress
|
||||
sed -i "s|3000|$(bashio::addon.ingress_port)|g" "${NGINX_CONFIG}"
|
||||
sed -i "s|SUBFOLDER|/|g" "${NGINX_CONFIG}"
|
||||
sed -i "s|CWS|8082|g" "${NGINX_CONFIG}"
|
||||
sed -i "s|REPLACE_HOME|${HOME:-/root}|g" "${NGINX_CONFIG}"
|
||||
sed -i "s|REPLACE_DOWNLOADS_PATH|${HOME:-/config}|g" "${NGINX_CONFIG}"
|
||||
sed -i '/proxy_buffering/a proxy_set_header Accept-Encoding "";' "${NGINX_CONFIG}"
|
||||
sed -i '/proxy_buffering/a sub_filter_once off;' "${NGINX_CONFIG}"
|
||||
sed -i '/proxy_buffering/a sub_filter_types *;' "${NGINX_CONFIG}"
|
||||
sed -i '/proxy_buffering/a sub_filter "vnc/index.html?autoconnect" "vnc/index.html?path=%%path%%/websockify?autoconnect";' "${NGINX_CONFIG}"
|
||||
sed -i "s|%%path%%|${SUBFOLDER:1}|g" "${NGINX_CONFIG}"
|
||||
|
||||
# Avoid content encoding on proxied responses to keep Selkies happy (handled by proxy_set_header Accept-Encoding insertion above)
|
||||
cp "${NGINX_CONFIG}" /etc/nginx/sites-enabled
|
||||
96
claude_desktop/rootfs/etc/nginx/includes/mime.types
Normal file
@@ -0,0 +1,96 @@
|
||||
types {
|
||||
text/html html htm shtml;
|
||||
text/css css;
|
||||
text/xml xml;
|
||||
image/gif gif;
|
||||
image/jpeg jpeg jpg;
|
||||
application/javascript js;
|
||||
application/atom+xml atom;
|
||||
application/rss+xml rss;
|
||||
|
||||
text/mathml mml;
|
||||
text/plain txt;
|
||||
text/vnd.sun.j2me.app-descriptor jad;
|
||||
text/vnd.wap.wml wml;
|
||||
text/x-component htc;
|
||||
|
||||
image/png png;
|
||||
image/svg+xml svg svgz;
|
||||
image/tiff tif tiff;
|
||||
image/vnd.wap.wbmp wbmp;
|
||||
image/webp webp;
|
||||
image/x-icon ico;
|
||||
image/x-jng jng;
|
||||
image/x-ms-bmp bmp;
|
||||
|
||||
font/woff woff;
|
||||
font/woff2 woff2;
|
||||
|
||||
application/java-archive jar war ear;
|
||||
application/json json;
|
||||
application/mac-binhex40 hqx;
|
||||
application/msword doc;
|
||||
application/pdf pdf;
|
||||
application/postscript ps eps ai;
|
||||
application/rtf rtf;
|
||||
application/vnd.apple.mpegurl m3u8;
|
||||
application/vnd.google-earth.kml+xml kml;
|
||||
application/vnd.google-earth.kmz kmz;
|
||||
application/vnd.ms-excel xls;
|
||||
application/vnd.ms-fontobject eot;
|
||||
application/vnd.ms-powerpoint ppt;
|
||||
application/vnd.oasis.opendocument.graphics odg;
|
||||
application/vnd.oasis.opendocument.presentation odp;
|
||||
application/vnd.oasis.opendocument.spreadsheet ods;
|
||||
application/vnd.oasis.opendocument.text odt;
|
||||
application/vnd.openxmlformats-officedocument.presentationml.presentation
|
||||
pptx;
|
||||
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
|
||||
xlsx;
|
||||
application/vnd.openxmlformats-officedocument.wordprocessingml.document
|
||||
docx;
|
||||
application/vnd.wap.wmlc wmlc;
|
||||
application/x-7z-compressed 7z;
|
||||
application/x-cocoa cco;
|
||||
application/x-java-archive-diff jardiff;
|
||||
application/x-java-jnlp-file jnlp;
|
||||
application/x-makeself run;
|
||||
application/x-perl pl pm;
|
||||
application/x-pilot prc pdb;
|
||||
application/x-rar-compressed rar;
|
||||
application/x-redhat-package-manager rpm;
|
||||
application/x-sea sea;
|
||||
application/x-shockwave-flash swf;
|
||||
application/x-stuffit sit;
|
||||
application/x-tcl tcl tk;
|
||||
application/x-x509-ca-cert der pem crt;
|
||||
application/x-xpinstall xpi;
|
||||
application/xhtml+xml xhtml;
|
||||
application/xspf+xml xspf;
|
||||
application/zip zip;
|
||||
|
||||
application/octet-stream bin exe dll;
|
||||
application/octet-stream deb;
|
||||
application/octet-stream dmg;
|
||||
application/octet-stream iso img;
|
||||
application/octet-stream msi msp msm;
|
||||
|
||||
audio/midi mid midi kar;
|
||||
audio/mpeg mp3;
|
||||
audio/ogg ogg;
|
||||
audio/x-m4a m4a;
|
||||
audio/x-realaudio ra;
|
||||
|
||||
video/3gpp 3gpp 3gp;
|
||||
video/mp2t ts;
|
||||
video/mp4 mp4;
|
||||
video/mpeg mpeg mpg;
|
||||
video/quicktime mov;
|
||||
video/webm webm;
|
||||
video/x-flv flv;
|
||||
video/x-m4v m4v;
|
||||
video/x-mng mng;
|
||||
video/x-ms-asf asx asf;
|
||||
video/x-ms-wmv wmv;
|
||||
video/x-msvideo avi;
|
||||
}
|
||||
15
claude_desktop/rootfs/etc/nginx/includes/proxy_params.conf
Normal file
@@ -0,0 +1,15 @@
|
||||
proxy_http_version 1.1;
|
||||
proxy_ignore_client_abort off;
|
||||
proxy_read_timeout 86400s;
|
||||
proxy_redirect off;
|
||||
proxy_send_timeout 86400s;
|
||||
proxy_max_temp_file_size 0;
|
||||
|
||||
proxy_set_header Accept-Encoding "";
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-NginX-Proxy true;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
1
claude_desktop/rootfs/etc/nginx/includes/resolver.conf
Normal file
@@ -0,0 +1 @@
|
||||
resolver 127.0.0.11 ipv6=off;
|
||||
@@ -0,0 +1,6 @@
|
||||
root /dev/null;
|
||||
server_name $hostname;
|
||||
|
||||
add_header X-Content-Type-Options nosniff;
|
||||
add_header X-XSS-Protection "1; mode=block";
|
||||
add_header X-Robots-Tag none;
|
||||
9
claude_desktop/rootfs/etc/nginx/includes/ssl_params.conf
Normal file
@@ -0,0 +1,9 @@
|
||||
ssl_protocols TLSv1.2;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:DHE-RSA-AES256-SHA;
|
||||
ssl_ecdh_curve secp384r1;
|
||||
ssl_session_timeout 10m;
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
ssl_session_tickets off;
|
||||
ssl_stapling on;
|
||||
ssl_stapling_verify on;
|
||||
3
claude_desktop/rootfs/etc/nginx/includes/upstream.conf
Normal file
@@ -0,0 +1,3 @@
|
||||
upstream backend {
|
||||
server 127.0.0.1:8080;
|
||||
}
|
||||
25
claude_desktop/rootfs/etc/s6-overlay/s6-rc.d/svc-headroom/run
Executable file
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# Headroom optimization proxy — runs ONLY as a local backend for the headroom MCP tools
|
||||
# (headroom_compress / headroom_retrieve, registered in 82-claude_tools.sh). It is NOT a
|
||||
# traffic router: no client's ANTHROPIC_BASE_URL is pointed at it, so the Claude Desktop
|
||||
# Electron app (which force-overrides ANTHROPIC_BASE_URL — headroom #869) and every other
|
||||
# client are unaffected. Without this backend the MCP tools cannot store/retrieve compressed
|
||||
# content and no savings are ever recorded.
|
||||
declare port=8787
|
||||
declare host=127.0.0.1
|
||||
|
||||
# Expose the built-in Headroom dashboard only when the add-on option is enabled
|
||||
# and Home Assistant has mapped the Headroom port. The port is mapped by default
|
||||
# in config.yaml, so users can open http://<ha-host>:8787/dashboard to inspect
|
||||
# live savings, while disabling install_headroom still leaves the service idle.
|
||||
if [[ -n "$(bashio::addon.port "${port}")" ]]; then
|
||||
host=0.0.0.0
|
||||
fi
|
||||
|
||||
if bashio::config.true 'install_headroom' && command -v headroom >/dev/null 2>&1; then
|
||||
bashio::log.info "svc-headroom: starting headroom proxy on ${host}:${port}; dashboard available at /dashboard when the port is mapped (MCP backend only; no client routing)"
|
||||
exec headroom proxy --host "${host}" --port "${port}" --code-aware
|
||||
fi
|
||||
|
||||
bashio::log.info "svc-headroom: install_headroom disabled or headroom not found; idling"
|
||||
exec sleep infinity
|
||||
@@ -0,0 +1 @@
|
||||
longrun
|
||||
34
claude_desktop/rootfs/usr/local/bin/claude-gains-report.sh
Executable file
@@ -0,0 +1,34 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# Hourly rtk + headroom token-savings snapshot for the add-on log.
|
||||
# Invoked by cron (see /defaults/crontabs/root); its stdout is redirected to /proc/1/fd/1,
|
||||
# so the report appears in the add-on log. Doubles as a heartbeat: if the numbers stop
|
||||
# growing, the corresponding tool has stopped working.
|
||||
# with-contenv supplies HOME from the s6 envdir, so this honors a custom `data_location`
|
||||
# (see 20-folders.sh) instead of hardcoding /data/data; it also makes bashio::config
|
||||
# available for the install_headroom gate below.
|
||||
export NO_COLOR=1 # keep the add-on log free of ANSI color codes
|
||||
export PATH="/lsiopy/bin:/usr/local/bin:/usr/bin:/bin:${PATH}"
|
||||
|
||||
have_rtk=false; command -v rtk >/dev/null 2>&1 && have_rtk=true
|
||||
have_headroom=false; command -v headroom >/dev/null 2>&1 && have_headroom=true
|
||||
|
||||
# headroom is pip-installed unconditionally at build time, so its binary is on PATH even
|
||||
# when install_headroom is off — gate on the same config svc-headroom checks, and only
|
||||
# fall back to have_headroom as a secondary availability guard.
|
||||
headroom_enabled=false
|
||||
if bashio::config.true 'install_headroom' && $have_headroom; then
|
||||
headroom_enabled=true
|
||||
fi
|
||||
|
||||
# Nothing to report if neither tool is active — stay quiet.
|
||||
if ! $have_rtk && ! $headroom_enabled; then exit 0; fi
|
||||
|
||||
echo "===== claude gains report $(date '+%Y-%m-%d %H:%M:%S') ====="
|
||||
if $headroom_enabled; then
|
||||
echo "--- headroom savings ---"
|
||||
headroom savings 2>&1 || echo "[warn] headroom savings failed"
|
||||
elif $have_rtk; then
|
||||
echo "--- rtk gain ---"
|
||||
rtk gain 2>&1 || echo "[warn] rtk gain failed"
|
||||
fi
|
||||
echo "===== end gains report ====="
|
||||
7
claude_desktop/updater.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"source": "github",
|
||||
"upstream_repo": "linuxserver/docker-baseimage-selkies",
|
||||
"github_fulltag": true,
|
||||
"slug": "claude_desktop",
|
||||
"paused": false
|
||||
}
|
||||
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 1.4 KiB |
BIN
codex/stats.png
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 1.7 KiB |
BIN
emby/stats.png
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 1.7 KiB |
BIN
ente/stats.png
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 1.6 KiB |
@@ -1,4 +1,7 @@
|
||||
|
||||
## 2.63.18 (2026-07-04)
|
||||
- Update to latest version from filebrowser/filebrowser (changelog : https://github.com/filebrowser/filebrowser/releases)
|
||||
|
||||
## 2.63.17 (2026-06-29)
|
||||
- Update to latest version from filebrowser/filebrowser (changelog : https://github.com/filebrowser/filebrowser/releases)
|
||||
|
||||
|
||||
@@ -124,4 +124,4 @@ schema:
|
||||
slug: filebrowser
|
||||
udev: true
|
||||
url: https://github.com/alexbelgium/hassio-addons
|
||||
version: "2.63.17"
|
||||
version: "2.63.18"
|
||||
|
||||
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 1.5 KiB |
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"github_beta": "true",
|
||||
"last_update": "2026-06-29",
|
||||
"last_update": "2026-07-04",
|
||||
"paused": false,
|
||||
"repository": "alexbelgium/hassio-addons",
|
||||
"slug": "filebrowser",
|
||||
"source": "github",
|
||||
"upstream_repo": "filebrowser/filebrowser",
|
||||
"upstream_version": "2.63.17"
|
||||
"upstream_version": "2.63.18"
|
||||
}
|
||||
|
||||