This commit is contained in:
ai-dev
2025-10-11 11:17:26 +02:00
parent 270cf38204
commit 8e559fa82c
27 changed files with 2449 additions and 1 deletions

97
.templates/.README.md Normal file
View File

@@ -0,0 +1,97 @@
# Home assistant add-on: alexbelgium
<!-- markdownlint-disable MD033 -->
[![Donate][donation-badge]](https://www.buymeacoffee.com/alexbelgium)
[![Donate][paypal-badge]](https://www.paypal.com/donate/?hosted_button_id=DZFULJZTP3UQA)
![update-badge](https://img.shields.io/github/last-commit/alexbelgium/hassio-addons?label=last%20update)
[donation-badge]: https://img.shields.io/badge/Buy%20me%20a%20coffee%20(no%20paypal)-%23d32f2f?logo=buy-me-a-coffee&style=flat&logoColor=white
[paypal-badge]: https://img.shields.io/badge/Buy%20me%20a%20coffee%20with%20Paypal-0070BA?logo=paypal&style=flat&logoColor=white
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/9c6cf10bdbba45ecb202d7f579b5be0e)](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)
[![GitHub Super-Linter](https://img.shields.io/github/actions/workflow/status/alexbelgium/hassio-addons/weekly-supelinter.yaml?label=Lint%20code%20base)](https://github.com/alexbelgium/hassio-addons/actions/workflows/weekly-supelinter.yaml)
[![Builder](https://img.shields.io/github/actions/workflow/status/alexbelgium/hassio-addons/onpush_builder.yaml?label=Builder)](https://github.com/alexbelgium/hassio-addons/actions/workflows/onpush_builder.yaml)
[![Statistics](https://github.com/alexbelgium/hassio-addons/workflows/Generate%20weekly%20stats/badge.svg)](https://github.com/alexbelgium/hassio-addons/actions/workflows/weekly_stats.yaml)
[support-badge]: https://camo.githubusercontent.com/f4dbb995049f512fdc97fcc9e022ac243fa38c408510df9d46c7467d0970d959/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f537570706f72742d7468726561642d677265656e2e737667
_Thanks to everyone having starred my repo! To star it click on the image below, then it will be on top right. Thanks!_
[![Stargazers repo roster for @alexbelgium/hassio-addons](https://reporoster.com/stars/alexbelgium/hassio-addons)](https://github.com/alexbelgium/hassio-addons/stargazers)
_Thanks to all contributors !_
[![contributors](https://contrib.rocks/image?repo=alexbelgium/hassio-addons)](https://github.com/alexbelgium/hassio-addons/graphs/contributors)
Stargazers locations :
![map](https://raw.githubusercontent.com/alexbelgium/hassio-addons/refs/heads/master/.github/stargazer_map.png)
## About
Home Assistant allows anyone to create add-on repositories to share their
add-ons for Home Assistant easily. This repository is one of those repositories,
providing extra Home Assistant add-ons for your installation.
The primary goal of this project is to provide you (as a Home Assistant user)
with additional, high quality, add-ons that allow you to take your automated
home to the next level.
## Installation
[![Add repository on my Home Assistant][repository-badge]][repository-url]
If you want to do add the repository manually, please follow the procedure highlighted in the [Home Assistant website](https://home-assistant.io/hassio/installing_third_party_addons). Use the following URL to add this repository: https://github.com/alexbelgium/hassio-addons
## Statistics
### Number of addons
- In the repository : %%STATS_ADDONS%%
- Installed : %%STATS_DOWNLOADS%%
### Top 3
1. %%STATS_ONE%%
2. %%STATS_TWO%%
3. %%STATS_THREE%%
### Architectures used
- %%STATS_AMD64%%
- %%STATS_AARCH64%%
- %%STATS_ARMV7%%
### Stars evolution
[![Star History Chart](https://api.star-history.com/svg?repos=alexbelgium/hassio-addons&type=Date)](https://star-history.com/#alexbelgium/hassio-addons&Date)
## Add-ons provided by this repository
%%ADDONS_LIST%%
## Support
Got questions?
You have several options to get them answered:
- The Home Assistant [Community Forum][forum].
- This repository issues list
[aarch64-badge]: https://img.shields.io/badge/aarch64--green.svg?logo=arm
[amd64-badge]: https://img.shields.io/badge/amd64--green.svg?logo=amd
[armv7-badge]: https://img.shields.io/badge/armv7--green.svg?logo=arm
[aarch64no-badge]: https://img.shields.io/badge/aarch64--orange.svg?logo=arm
[amd64no-badge]: https://img.shields.io/badge/amd64--orange.svg?logo=amd
[armv7no-badge]: https://img.shields.io/badge/armv7--orange.svg?logo=arm
[ingress-badge]: https://img.shields.io/badge/-ingress-blueviolet.svg?logo=Ingress
[mariadb-badge]: https://img.shields.io/badge/Service-MariaDB-green.svg?logo=mariadb&logoColor=white
[mqtt-badge]: https://img.shields.io/badge/Service-MQTT-green.svg?logo=chromecast&logoColor=white
[localdisks-badge]: https://img.shields.io/badge/Mounts-localdisks-blue.svg
[smb-badge]: https://img.shields.io/badge/Mounts-networkdisks-blue.svg
[full_access-badge]: https://img.shields.io/badge/Requires-full_access-orange.svg
[forum]: https://community.home-assistant.io/t/alexbelgium-repo-60-addons
[repository-badge]: https://img.shields.io/badge/Add%20repository%20to%20my-Home%20Assistant-41BDF5?logo=home-assistant&style=for-the-badge
[repository-url]: https://my.home-assistant.io/redirect/supervisor_add_addon_repository/?repository_url=https%3A%2F%2Fgithub.com%2Falexbelgium%2Fhassio-addons

View File

@@ -0,0 +1,51 @@
#!/bin/bash
set -e
# If dockerfile failed install manually
##############################
# Automatic modules download #
##############################
if [ -e "/MODULESFILE" ]; then
MODULES=$(< /MODULESFILE)
MODULES="${MODULES:-00-banner.sh}"
echo "Executing modules script : $MODULES"
if ! command -v bash > /dev/null 2> /dev/null; then (apt-get update && apt-get install -yqq --no-install-recommends bash || apk add --no-cache bash) > /dev/null; fi \
&& if ! command -v curl > /dev/null 2> /dev/null; then (apt-get update && apt-get install -yqq --no-install-recommends curl || apk add --no-cache curl) > /dev/null; fi \
&& apt-get update && apt-get install -yqq --no-install-recommends ca-certificates || apk add --no-cache ca-certificates > /dev/null || true \
&& mkdir -p /etc/cont-init.d \
&& for scripts in $MODULES; do echo "$scripts" && curl -f -L -s -S "https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/.templates/$scripts" -o /etc/cont-init.d/"$scripts" && [ "$(sed -n '/\/bin/p;q' /etc/cont-init.d/"$scripts")" != "" ] || (echo "script failed to install $scripts" && exit 1); done \
&& chmod -R 755 /etc/cont-init.d
fi
#######################
# Automatic installer #
#######################
if [ -e "/ENVFILE" ]; then
PACKAGES=$(< /ENVFILE)
echo "Executing dependency script with custom elements : $PACKAGES"
if ! command -v bash > /dev/null 2> /dev/null; then (apt-get update && apt-get install -yqq --no-install-recommends bash || apk add --no-cache bash) > /dev/null; fi \
&& if ! command -v curl > /dev/null 2> /dev/null; then (apt-get update && apt-get install -yqq --no-install-recommends curl || apk add --no-cache curl) > /dev/null; fi \
&& curl -f -L -s -S "https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/.templates/ha_automatic_packages.sh" --output /ha_automatic_packages.sh \
&& chmod 755 /ha_automatic_packages.sh \
&& eval /./ha_automatic_packages.sh "${PACKAGES:-}" \
&& rm /ha_automatic_packages.sh
fi
if [ -e "/MODULESFILE" ] && [ ! -f /ha_entrypoint.sh ]; then
for scripts in $MODULES; do
echo "$scripts : executing"
chown "$(id -u)":"$(id -g)" /etc/cont-init.d/"$scripts"
chmod a+x /etc/cont-init.d/"$scripts"
/./etc/cont-init.d/"$scripts" || echo "/etc/cont-init.d/$scripts: exiting $?"
rm /etc/cont-init.d/"$scripts"
done | tac
fi
#######################
# Correct permissions #
#######################
[ -d /etc/services.d ] && chmod -R 777 /etc/services.d
[ -d /etc/cont-init.d ] && chmod -R 777 /etc/cont-init.d

85
.templates/00-banner.sh Normal file
View File

@@ -0,0 +1,85 @@
#!/usr/bin/with-contenv bashio
# shellcheck shell=bash disable=SC2016
set -e
# ==============================================================================
# Displays a simple add-on banner on startup
# ==============================================================================
if ! bashio::supervisor.ping 2> /dev/null; then
# Degraded mode if no homeassistant
bashio::log.blue \
'-----------------------------------------------------------'
bashio::log.blue "Starting addon without HA support"
bashio::log.blue "Version : ${BUILD_VERSION:-1.0}"
bashio::log.blue "Please use Docker Compose for env variables"
bashio::log.blue \
'-----------------------------------------------------------'
# Use environment variables instead of addon options
echo "... convert scripts to use environment variables instead of addon options"
while IFS= read -r scripts; do
[[ "$scripts" == *"00-banner.sh"* ]] && continue
sed -i -e 's/bashio::config.has_value[[:space:]]*["'"'"']\([^"'"'"']*\)["'"'"']/[ ! -z "${\1:-}" ]/g' \
-e 's/bashio::config.true[[:space:]]*["'"'"']\([^"'"'"']*\)["'"'"']/[ ! -z "${\1:-}" ] \&\& [ "${\1:-}" = "true" ]/g' \
-e 's/\$(bashio::config[[:space:]]*["'"'"']\([^"'"'"']*\)["'"'"'])/${\1:-}/g' \
-e 's/\$(bashio::addon.port[[:space:]]*["'"'"']\([0-9]*\)["'"'"'])/${\1:-}/g' \
-e 's/bashio::config.require.ssl/true/g' \
-e 's/\$(bashio::addon.ingress_port)/""/g' \
-e 's/\$(bashio::addon.ingress_entry)/""/g' \
-e 's/\$(bashio::addon.ip_address)/""/g' "$scripts"
done < <(grep -srl "bashio" /etc/cont-init.d /custom-services.d /etc/services.d /etc/s6-overlay)
exit 0
fi
bashio::log.blue \
'-----------------------------------------------------------'
bashio::log.blue " Add-on: $(bashio::addon.name)"
bashio::log.blue " $(bashio::addon.description)"
bashio::log.blue \
'-----------------------------------------------------------'
bashio::log.blue " Add-on version: $(bashio::addon.version)"
if bashio::var.true "$(bashio::addon.update_available)"; then
bashio::log.magenta ' There is an update available for this add-on!'
bashio::log.magenta \
" Latest add-on version: $(bashio::addon.version_latest)"
bashio::log.magenta ' Please consider upgrading as soon as possible.'
else
bashio::log.green ' You are running the latest version of this add-on.'
fi
bashio::log.blue " System: $(bashio::info.operating_system)"
bashio::log.blue " Architecture: $(bashio::info.arch) / $(bashio::info.machine)"
bashio::log.blue " Home Assistant Core: $(bashio::info.homeassistant)"
bashio::log.blue " Home Assistant Supervisor: $(bashio::info.supervisor)"
bashio::log.blue \
'-----------------------------------------------------------'
bashio::log.blue \
' Please, share the above information when looking for help'
bashio::log.blue \
' or support in, e.g., GitHub, forums'
bashio::log.blue \
'-----------------------------------------------------------'
bashio::log.green \
' Provided by: https://github.com/alexbelgium/hassio-addons '
bashio::log.blue \
'-----------------------------------------------------------'
# ==============================================================================
# Global actions for all addons
# ==============================================================================
if bashio::config.has_value "PUID" && bashio::config.has_value "PGID" && id abc &> /dev/null; then
bashio::log.green ' Defining permissions for main user : '
PUID="$(bashio::config "PUID")"
PGID="$(bashio::config "PGID")"
usermod -o -u "$PUID" abc
groupmod -o -g "$PGID" abc
bashio::log.blue "User UID: $(id -u abc)"
bashio::log.blue "User GID: $(id -g abc)"
bashio::log.blue \
'-----------------------------------------------------------'
fi
# Clean bashrc file safely
if [ -f ~/.bashrc ]; then : > ~/.bashrc; fi

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Color comments
#! Red
#? Question
#// Done
#todo To do
#* Green

View File

@@ -0,0 +1,19 @@
#!/usr/bin/with-contenv bashio
# shellcheck shell=bash
set -e
# ==============================================================================
# Displays a simple add-on banner on startup
# ==============================================================================
echo ""
bashio::log.yellow "####################"
bashio::log.yellow "# ADDON deprecated #"
bashio::log.yellow "####################"
echo ""
bashio::log.yellow "This addon is now supported in the official HA community repository. You should migrate your data as soon as possible! This addon will not be supported and updates might stop in the future."
bashio::log.yellow "You'll likely get better support as the official community is supported by the HA devs ! If some features from the official add-on are missing you should raise a request on the ha community add-ons repo"
bashio::log.yellow "Thanks for all users over the years !"
echo ""
sleep 5

131
.templates/00-global_var.sh Normal file
View File

@@ -0,0 +1,131 @@
#!/usr/bin/with-contenv bashio
# shellcheck shell=bash
set -e
if ! bashio::supervisor.ping 2> /dev/null; then
echo "..."
exit 0
fi
###################################
# Export all addon options as env #
###################################
# For all keys in options.json
JSONSOURCE="/data/options.json"
# Define secrets location
if [ -f /homeassistant/secrets.yaml ]; then
SECRETSOURCE="/homeassistant/secrets.yaml"
elif [ -f /config/secrets.yaml ]; then
SECRETSOURCE="/config/secrets.yaml"
else
SECRETSOURCE="false"
fi
# Export keys as env variables
# echo "All addon options were exported as variables"
mapfile -t arr < <(jq -r 'keys[]' "${JSONSOURCE}")
# Escape special characters using printf and enclose in double quotes
sanitize_variable() {
local raw="$1"
local escaped
if [[ "$raw" == \[* ]]; then
echo "One of your options is an array, skipping"
return
fi
printf -v escaped '%q' "$raw"
# Do not espace spaces
escaped="${escaped//\\ / }"
if [[ "$raw" == "$escaped" ]]; then
printf '%s' "$raw"
else
printf '%s' "$escaped"
fi
}
for KEYS in "${arr[@]}"; do
# export key
VALUE=$(jq -r --raw-output ".\"$KEYS\"" "$JSONSOURCE")
# Check if the value is an array
if [[ "$VALUE" == \[* ]]; then
bashio::log.warning "One of your option is an array, skipping"
else
# Sanitize variable
VALUE=$(sanitize_variable "$VALUE")
# If value is empty, returns an empty value
if [[ -z "$VALUE" ]]; then
line="${KEYS}=''"
else
# Continue for single values
line="${KEYS}='${VALUE//\'/\'\\\'\'}'"
fi
# Check if secret
if [[ "${line}" == *"!secret "* ]]; then
echo "secret detected"
# Get argument
secret=${line#*secret }
# Remove trailing ' or "
secret="${secret%[\"\']}"
# Stop if secret file not mounted
if [[ "$SECRETSOURCE" == "false" ]]; then
bashio::log.warning "Homeassistant config not mounted, secrets are not supported"
continue
fi
# Check if single match
secretnum=$(sed -n "/$secret:/=" "$SECRETSOURCE")
[[ "$secretnum" == *' '* ]] && bashio::exit.nok "There are multiple matches for your password name. Please check your secrets.yaml file"
# Get text
secret=$(sed -n "/$secret:/p" "$SECRETSOURCE")
secret=${secret#*: }
line="${line%%=*}='$secret'"
VALUE="$secret"
fi
# text
if bashio::config.false "verbose" || [[ "${KEYS,,}" == *"pass"* ]]; then
bashio::log.blue "${KEYS}=******"
else
bashio::log.blue "$line"
fi
######################################
# Export the variable to run scripts #
######################################
# shellcheck disable=SC2163
export "$line"
# export to python
if command -v "python3" &> /dev/null; then
[ ! -f /env.py ] && echo "import os" > /env.py
# Escape \
VALUEPY="${VALUE//\\/\\\\}"
# Avoid " and '
VALUEPY="${VALUEPY//[\"\']/}"
echo "os.environ['${KEYS}'] = '$VALUEPY'" >> /env.py
python3 /env.py
fi
# set .env
echo "$line" >> /.env || true
# set /etc/environment
mkdir -p /etc
echo "$line" >> /etc/environment
# For non s6
if cat /etc/services.d/*/*run* &> /dev/null; then sed -i "1a export $line" /etc/services.d/*/*run* 2> /dev/null; fi
if cat /etc/cont-init.d/*.sh &> /dev/null; then sed -i "1a export $line" /etc/cont-init.d/*.sh 2> /dev/null; fi
# For s6
if [ -d /var/run/s6/container_environment ]; then printf "%s" "${VALUE}" > /var/run/s6/container_environment/"${KEYS}"; fi
echo "export ${KEYS}='${VALUE}'" >> ~/.bashrc
fi
done
################
# Set timezone #
################
set +eu
if [ -n "$TZ" ] && [ -f /etc/localtime ]; then
if [ -f /usr/share/zoneinfo/"$TZ" ]; then
echo "Timezone set from $(cat /etc/timezone) to $TZ"
ln -snf /usr/share/zoneinfo/"$TZ" /etc/localtime && echo "$TZ" > /etc/timezone
fi
fi

View File

@@ -109,4 +109,4 @@ if bashio::config.has_value 'localdisks'; then
)
done
fi
fi

357
.templates/00-smb_mounts.sh Normal file
View File

@@ -0,0 +1,357 @@
#!/usr/bin/with-contenv bashio
# shellcheck shell=bash
# shellcheck disable=
set -e
if ! bashio::supervisor.ping 2> /dev/null; then
bashio::log.blue "Disabled : please use another method"
exit 0
fi
bashio::log.notice "This script is used to mount remote smb/cifs/nfs shares. Instructions here : https://github.com/alexbelgium/hassio-addons/wiki/Mounting-remote-shares-in-Addons"
####################
# DEFINE FUNCTIONS #
####################
test_mount() {
# Set initial test
MOUNTED=false
ERROR_MOUNT=false
# Exit if not mounted
if ! mountpoint -q /mnt/"$diskname"; then
return 0
fi
# Exit if can't write
[[ -e "/mnt/$diskname/testaze" ]] && rm -r "/mnt/$diskname/testaze"
# shellcheck disable=SC2015
mkdir "/mnt/$diskname/testaze" && touch "/mnt/$diskname/testaze/testaze" && rm -r "/mnt/$diskname/testaze" || ERROR_MOUNT=true
# Only CIFS has the noserverino fallback
if [[ "$ERROR_MOUNT" == "true" && "$FSTYPE" == "cifs" ]]; then
# Test write permissions
if [[ "$MOUNTOPTIONS" == *"noserverino"* ]]; then
bashio::log.fatal "Disk is mounted, however unable to write in the shared disk. Please check UID/GID for permissions, and if the share is rw"
else
MOUNTOPTIONS="$MOUNTOPTIONS,noserverino"
echo "... testing with noserverino"
mount_drive "$MOUNTOPTIONS"
return 0
fi
fi
# Set correctly mounted bit
MOUNTED=true
return 0
}
mount_drive() {
# Define options
MOUNTED=true
MOUNTOPTIONS="$1"
# Try mounting (type depends on detected FSTYPE)
if [[ "$FSTYPE" == "cifs" ]]; then
mount -t cifs -o "$MOUNTOPTIONS" "$disk" /mnt/"$diskname" 2> ERRORCODE || MOUNTED=false
elif [[ "$FSTYPE" == "nfs" ]]; then
mount -t nfs -o "$MOUNTOPTIONS" "$disk" /mnt/"$diskname" 2> ERRORCODE || MOUNTED=false
fi
# Test if successful
if [[ "$MOUNTED" == "true" ]]; then
# shellcheck disable=SC2015
test_mount
fi
}
####################
# MOUNT NETWORK SHARES #
####################
if bashio::config.has_value 'networkdisks'; then
# Alert message that it is a new code
if [[ "$(date +"%Y%m%d")" -lt "20240201" ]]; then
bashio::log.warning "------------------------"
bashio::log.warning "This is a new code, please report any issues on https://github.com/alexbelgium/hassio-addons"
bashio::log.warning "------------------------"
fi
echo 'Mounting network share(s)...'
####################
# Define variables #
####################
# Set variables
MOREDISKS=$(bashio::config 'networkdisks')
USERNAME=$(bashio::config 'cifsusername')
PASSWORD=$(bashio::config 'cifspassword')
SMBVERS=""
SECVERS=""
CHARSET=",iocharset=utf8"
# Clean data (keeps NFS entries intact)
MOREDISKS=${MOREDISKS// \/\//,\/\/}
MOREDISKS=${MOREDISKS//, /,}
MOREDISKS=${MOREDISKS// /"\040"}
# Is domain set (CIFS only)
DOMAIN=""
DOMAINCLIENT=""
if bashio::config.has_value 'cifsdomain'; then
echo "... using domain $(bashio::config 'cifsdomain')"
DOMAIN=",domain=$(bashio::config 'cifsdomain')"
DOMAINCLIENT="--workgroup=$(bashio::config 'cifsdomain')"
fi
# Is UID/GID set (used for CIFS mount options)
PUID=",uid=$(id -u)"
PGID=",gid=$(id -g)"
if bashio::config.has_value 'PUID' && bashio::config.has_value 'PGID'; then
echo "... using PUID $(bashio::config 'PUID') and PGID $(bashio::config 'PGID')"
PUID=",uid=$(bashio::config 'PUID')"
PGID=",gid=$(bashio::config 'PGID')"
fi
##################
# Mounting disks #
##################
# shellcheck disable=SC2086
for disk in ${MOREDISKS//,/ }; do # Separate comma separated values
# Clean name of network share
# shellcheck disable=SC2116,SC2001
disk=$(echo $disk | sed "s,/$,,") # Remove / at end of name
disk="${disk//"\040"/ }" # replace \040 with space
# Detect filesystem type by pattern (CIFS: //ip/share ; NFS: ip:/export[/path] or nfs://ip:/export[/path])
FSTYPE="cifs"
if [[ "$disk" =~ ^nfs:// ]]; then
FSTYPE="nfs"
disk="${disk#nfs://}"
elif [[ "$disk" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+:/.+ ]]; then
FSTYPE="nfs"
fi
# Determine server for reachability checks
if [[ "$FSTYPE" == "cifs" ]]; then
server="$(echo "$disk" | grep -E -o "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+")"
else
server="${disk%%:*}"
fi
diskname="$disk"
diskname="${diskname//\\//}" # replace \ with /
diskname="${diskname##*/}" # Get only last part of the name
MOUNTED=false
SMBVERS_FORCE=""
SECVERS_FORCE=""
# Start
echo "... mounting ($FSTYPE) $disk"
# Data validation
if [[ "$FSTYPE" == "cifs" ]]; then
if [[ ! "$disk" =~ ^.*+[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+[/]+.*+$ ]]; then
bashio::log.fatal "...... the structure of your \"networkdisks\" option : \"$disk\" doesn't seem correct, please use a structure like //123.12.12.12/sharedfolder,//123.12.12.12/sharedfolder2. If you don't use it, you can simply remove the text, this will avoid this error message in the future."
touch ERRORCODE
continue
fi
else
if [[ ! "$disk" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+:/.+ ]]; then
bashio::log.fatal "...... invalid NFS path \"$disk\". Use a structure like 123.12.12.12:/export/path"
touch ERRORCODE
continue
fi
fi
# Prepare mount point
mkdir -p /mnt/"$diskname"
chown root:root /mnt/"$diskname"
# Quickly try to mount with defaults
if [[ "$FSTYPE" == "cifs" ]]; then
mount_drive "rw,file_mode=0775,dir_mode=0775,username=${USERNAME},password=${PASSWORD},nobrl${SMBVERS}${SECVERS}${PUID}${PGID}${CHARSET}${DOMAIN}"
elif [[ "$FSTYPE" == "nfs" ]]; then
mount_drive "rw,nfsvers=4.2,proto=tcp,hard,timeo=600,retrans=2"
fi
# Deeper analysis if failed
if [ "$MOUNTED" = false ]; then
if [[ "$FSTYPE" == "cifs" ]]; then
# Does server exist (SMB port 445)
output="$(nmap -F $server -T5 -oG -)"
if ! echo "$output" | grep 445/open &> /dev/null; then
if echo "$output" | grep /open &> /dev/null; then
bashio::log.fatal "...... $server is reachable but SMB port not opened, stopping script"
touch ERRORCODE
continue
else
bashio::log.fatal "...... fatal : $server not reachable, is it correct"
touch ERRORCODE
continue
fi
else
echo "...... $server is confirmed reachable"
fi
# Are credentials correct
OUTPUT="$(smbclient -t 2 -L "$disk" -U "$USERNAME"%"$PASSWORD" -c "exit" $DOMAINCLIENT 2>&1 || true)"
if echo "$OUTPUT" | grep -q "LOGON_FAILURE"; then
bashio::log.fatal "...... incorrect Username, Password, or Domain! Script will stop."
touch ERRORCODE
# Should there be a workgroup
if ! smbclient -t 2 -L $disk -N $DOMAINCLIENT -c "exit" &> /dev/null; then
bashio::log.fatal "...... perhaps a workgroup must be specified"
touch ERRORCODE
fi
continue
elif echo "$OUTPUT" | grep -q "tree connect failed" || echo "$OUTPUT" | grep -q "NT_STATUS_CONNECTION_DISCONNECTED"; then
echo "... using SMBv1"
bashio::log.warning "...... share reachable only with legacy SMBv1 (NT1) negotiation. Forcing SMBv1 options."
SMBVERS_FORCE=",vers=1.0"
SECVERS_FORCE=",sec=ntlm"
elif ! echo "$OUTPUT" | grep -q "Disk"; then
echo "... testing path"
bashio::log.fatal "...... no shares found. Invalid or inaccessible SMB path?"
else
echo "...... credentials are valid"
fi
# Extracting SMB versions and normalize output
# shellcheck disable=SC2210,SC2094
SMBVERS="$(nmap --script smb-protocols "$server" -p 445 2> 1 | awk '/ [0-9]/' | awk '{print $NF}' | cut -c -3 | sort -V | tail -n 1 || true)"
# Avoid :
SMBVERS="${SMBVERS/:/.}"
# Manage output
if [ -n "$SMBVERS" ]; then
case $SMBVERS in
"202" | "200" | "20")
SMBVERS="2.0"
;;
21)
SMBVERS="2.1"
;;
302)
SMBVERS="3.02"
;;
311)
SMBVERS="3.1.1"
;;
"3.1")
echo "SMB 3.1 detected, converting to 3.0"
SMBVERS="3.0"
;;
esac
echo "...... SMB version detected : $SMBVERS"
SMBVERS=",vers=$SMBVERS"
elif smbclient -t 2 -L "$server" -m NT1 -N $DOMAINCLIENT &> /dev/null; then
echo "...... SMB version : only SMBv1 is supported, this can lead to issues"
SECVERS=",sec=ntlm"
SMBVERS=",vers=1.0"
else
echo "...... SMB version : couldn't detect, default used"
SMBVERS=""
fi
# Apply forced SMBv1 options when initial connection required NT1 fallback
if [[ -n "$SMBVERS_FORCE" ]]; then
if [[ -z "$SMBVERS" ]]; then
SMBVERS="$SMBVERS_FORCE"
fi
if [[ -z "$SECVERS" ]]; then
SECVERS="$SECVERS_FORCE"
fi
fi
# Ensure the Samba client allows SMBv1 when those options are required
if [[ "${SMBVERS}${SMBVERS_FORCE}" == *"vers=1.0"* ]]; then
if [[ -f /etc/samba/smb.conf ]]; then
bashio::log.warning "...... enabling SMBv1 support in Samba client configuration"
sed -i '/\[global\]/!b;n;/client min protocol = NT1/!a\
client min protocol = NT1' /etc/samba/smb.conf
fi
fi
# Test with different security versions
#######################################
for SECVERS in "$SECVERS" ",sec=ntlmv2" ",sec=ntlmssp" ",sec=ntlmsspi" ",sec=krb5i" ",sec=krb5" ",sec=ntlm" ",sec=ntlmv2i"; do
if [ "$MOUNTED" = false ]; then
mount_drive "rw,file_mode=0775,dir_mode=0775,username=${USERNAME},password=${PASSWORD},nobrl${SMBVERS}${SECVERS}${PUID}${PGID}${CHARSET}${DOMAIN}"
fi
done
elif [[ "$FSTYPE" == "nfs" ]]; then
# Add NFS-specific port check (2049) similar to SMB (445)
output="$(nmap -F $server -T5 -oG -)"
if ! echo "$output" | grep -E '(2049|111)/open' &> /dev/null; then
bashio::log.fatal "...... $server is reachable but NFS ports not open"
continue
fi
# NFS fallback attempts: try common versions until one works
for NFVER in 4.2 4.1 4 3; do
if [ "$MOUNTED" = false ]; then
mount_drive "rw,nfsvers=${NFVER},proto=tcp"
fi
done
fi
fi
# Messages
if [ "$MOUNTED" = true ]; then
bashio::log.info "...... $disk successfully mounted to /mnt/$diskname with options ${MOUNTOPTIONS/$PASSWORD/XXXXXXXXXX}"
# Remove errorcode
if [ -f ERRORCODE ]; then
rm ERRORCODE
fi
# Alert if smbv1
if [[ "$FSTYPE" == "cifs" && "$MOUNTOPTIONS" == *"1.0"* ]]; then
bashio::log.warning ""
bashio::log.warning "Your smb system requires smbv1. This is an obsolete protocol. Please correct this to prevent issues."
bashio::log.warning ""
fi
else
# Mounting failed messages
if [[ "$FSTYPE" == "cifs" ]]; then
bashio::log.fatal "Error, unable to mount $disk to /mnt/$diskname with username $USERNAME, $PASSWORD. Please check your remote share path, username, password, domain, try putting 0 in UID and GID"
bashio::log.fatal "Here is some debugging info :"
smbclient -t 2 -L $disk -U "$USERNAME%$PASSWORD" -c "exit"
SMBVERS=""
SECVERS=""
PUID=""
PGID=""
CHARSET=""
mount_drive "rw,file_mode=0775,dir_mode=0775,username=${USERNAME},password=${PASSWORD},nobrl${SMBVERS}${SECVERS}${PUID}${PGID}${CHARSET}${DOMAIN}"
elif [[ "$FSTYPE" == "nfs" ]]; then
bashio::log.fatal "Error, unable to mount NFS share $disk to /mnt/$diskname. Please check the export path and that NFS server allows this client (and NFSv4)."
# last-ditch try with very basic options
mount_drive "rw"
fi
bashio::log.fatal "Error read : $(< ERRORCODE), addon will stop in 1 min"
# clean folder
umount "/mnt/$diskname" 2> /dev/null || true
rmdir "/mnt/$diskname" || true
# Stop addon
bashio::addon.stop
fi
done
fi

View File

@@ -0,0 +1,202 @@
#!/usr/bin/with-contenv bashio
# shellcheck shell=bash
##################
# INITIALIZATION #
##################
# Disable if config not present
if [ ! -d /config ] || ! bashio::supervisor.ping 2> /dev/null; then
echo "..."
exit 0
fi
# Define slug
slug="${HOSTNAME/-/_}"
slug="${slug#*_}"
# Check type of config folder
if [ ! -f /config/configuration.yaml ] && [ ! -f /config/configuration.json ]; then
# New config location
CONFIGLOCATION="/config"
CONFIGFILEBROWSER="/addon_configs/${HOSTNAME/-/_}/config.yaml"
else
# Legacy config location
CONFIGLOCATION="/config/addons_config/${slug}"
CONFIGFILEBROWSER="/homeassistant/addons_config/$slug/config.yaml"
fi
# Default location
mkdir -p "$CONFIGLOCATION" || true
CONFIGSOURCE="$CONFIGLOCATION"/config.yaml
# Is there a custom path
if bashio::config.has_value 'CONFIG_LOCATION'; then
CONFIGSOURCE=$(bashio::config "CONFIG_LOCATION")
if [[ "$CONFIGSOURCE" == *"."* ]]; then
CONFIGSOURCE=$(dirname "$CONFIGSOURCE")
fi
# If does not end by config.yaml, remove trailing slash and add config.yaml
if [[ "$CONFIGSOURCE" != *".yaml" ]]; then
CONFIGSOURCE="${CONFIGSOURCE%/}"/config.yaml
fi
# Check if config is located in an acceptable location
LOCATIONOK=""
for location in "/share" "/config" "/data"; do
if [[ "$CONFIGSOURCE" == "$location"* ]]; then
LOCATIONOK=true
fi
done
if [ -z "$LOCATIONOK" ]; then
bashio::log.red "Watch-out: your CONFIG_LOCATION values can only be set in /share, /config or /data (internal to addon). It will be reset to the default location: $CONFIGLOCATION/config.yaml"
CONFIGSOURCE="$CONFIGLOCATION"/config.yaml
fi
fi
# Migrate if needed
if [[ "$CONFIGLOCATION" == "/config" ]]; then
# Migrate file
if [ -f "/homeassistant/addons_config/${slug}/config.yaml" ] && [ ! -L "/homeassistant/addons_config/${slug}" ]; then
echo "Migrating config.yaml to new config location"
mv "/homeassistant/addons_config/${slug}/config.yaml" /config/config.yaml
fi
# Migrate option
if [[ "$(bashio::config "CONFIG_LOCATION")" == "/config/addons_config"* ]] && [ -f /config/config.yaml ]; then
bashio::addon.option "CONFIG_LOCATION" "/config/config.yaml"
CONFIGSOURCE="/config/config.yaml"
fi
fi
if [[ "$CONFIGSOURCE" != *".yaml" ]]; then
bashio::log.error "Something is going wrong in the config location, quitting"
exit 1
fi
# Permissions
if [[ "$CONFIGSOURCE" == *".yaml" ]]; then
echo "Setting permissions for the config.yaml directory"
mkdir -p "$(dirname "${CONFIGSOURCE}")"
chmod -R 755 "$(dirname "${CONFIGSOURCE}")" 2> /dev/null
fi
####################
# LOAD CONFIG.YAML #
####################
echo ""
bashio::log.green "Load environment variables from $CONFIGSOURCE if existing"
if [[ "$CONFIGSOURCE" == "/config"* ]]; then
bashio::log.green "If accessing the file with filebrowser it should be mapped to $CONFIGFILEBROWSER"
else
bashio::log.green "If accessing the file with filebrowser it should be mapped to $CONFIGSOURCE"
fi
bashio::log.green "---------------------------------------------------------"
bashio::log.notice "This script is used to export custom environment variables at start of the addon. Instructions here : https://github.com/alexbelgium/hassio-addons/wiki/Add-Environment-variables-to-your-Addon"
echo ""
# Check if config file is there, or create one from template
if [ ! -f "$CONFIGSOURCE" ]; then
echo "... no config file, creating one from template. Please customize the file in $CONFIGSOURCE before restarting."
# Create folder
mkdir -p "$(dirname "${CONFIGSOURCE}")"
# Placing template in config
if [ -f /templates/config.yaml ]; then
# Use available template
cp /templates/config.yaml "$(dirname "${CONFIGSOURCE}")"
else
# Download template
TEMPLATESOURCE="https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/.templates/config.template"
curl -f -L -s -S "$TEMPLATESOURCE" --output "$CONFIGSOURCE"
fi
fi
# Check if there are lines to read
cp "$CONFIGSOURCE" /tempenv
sed -i '/^#/d' /tempenv
sed -i '/^[[:space:]]*$/d' /tempenv
sed -i '/^$/d' /tempenv
echo "" >> /tempenv
# Exit if empty
if [ ! -s /tempenv ]; then
bashio::log.green "... no env variables found, exiting"
exit 0
fi
# Check if yaml is valid
EXIT_CODE=0
yamllint -d relaxed /tempenv &> ERROR || EXIT_CODE=$?
if [ "$EXIT_CODE" != 0 ]; then
cat ERROR
bashio::log.yellow "... config file has an invalid yaml format. Please check the file in $CONFIGSOURCE. Errors list above."
fi
# converts yaml to variables
sed -i 's/: /=/' /tempenv
# Look where secrets.yaml is located
SECRETSFILE="/config/secrets.yaml"
if [ ! -f "$SECRETSFILE" ]; then SECRETSFILE="/homeassistant/secrets.yaml"; fi
while IFS= read -r line; do
# Skip empty lines
if [[ -z "$line" ]]; then
continue
fi
# Check if secret
if [[ "$line" == *!secret* ]]; then
echo "Secret detected"
if [ ! -f "$SECRETSFILE" ]; then
bashio::log.fatal "Secrets file not found in $SECRETSFILE, $line skipped"
continue
fi
secret=$(echo "$line" | sed 's/.*!secret \(.*\)/\1/')
# Check if single match
secretnum=$(sed -n "/$secret:/=" "$SECRETSFILE")
if [[ $(echo "$secretnum" | grep -q ' ') ]]; then
bashio::exit.nok "There are multiple matches for your password name. Please check your secrets.yaml file"
fi
# Get text
secret_value=$(sed -n "/$secret:/s/.*: //p" "$SECRETSFILE")
line="${line%%=*}='$secret_value'"
fi
# Data validation
if [[ "$line" =~ ^[^[:space:]]+.+[=].+$ ]]; then
# extract keys and values
KEYS="${line%%=*}"
VALUE="${line#*=}"
# Check if VALUE is quoted
#if [[ "$VALUE" != \"*\" ]] && [[ "$VALUE" != \'*\' ]]; then
# VALUE="\"$VALUE\""
#fi
line="${KEYS}=${VALUE}"
export "$line"
# export to python
if command -v "python3" &> /dev/null; then
[ ! -f /env.py ] && echo "import os" > /env.py
# Escape single quotes in VALUE
VALUE_ESCAPED="${VALUE//\'/\'\"\'\"\'}"
echo "os.environ['${KEYS}'] = '${VALUE_ESCAPED}'" >> /env.py
python3 /env.py
fi
# set .env
echo "$line" >> /.env
# set environment
mkdir -p /etc
echo "$line" >> /etc/environment
# Export to scripts
if cat /etc/services.d/*/*run* &> /dev/null; then sed -i "1a export $line" /etc/services.d/*/*run* 2> /dev/null; fi
if cat /etc/cont-init.d/*run* &> /dev/null; then sed -i "1a export $line" /etc/cont-init.d/*run* 2> /dev/null; fi
# For s6
if [ -d /var/run/s6/container_environment ]; then printf "%s" "${VALUE}" > /var/run/s6/container_environment/"${KEYS}"; fi
echo "export $line" >> ~/.bashrc
# Show in log
if ! bashio::config.false "verbose"; then bashio::log.blue "$line"; fi
else
bashio::log.red "Skipping line that does not follow the correct structure: $line"
fi
done < "/tempenv"
rm /tempenv

View File

@@ -0,0 +1,66 @@
#!/usr/bin/with-contenv bashio
# shellcheck shell=bash
set -e
##################
# INITIALIZATION #
##################
# Exit if /config is not mounted or HA not used
if [ ! -d /config ] || ! bashio::supervisor.ping 2> /dev/null; then
echo "..."
exit 0
fi
# Define slug
slug="${HOSTNAME/-/_}"
slug="${slug#*_}"
# Check type of config folder
if [ ! -f /config/configuration.yaml ] && [ ! -f /config/configuration.json ]; then
# New config location
CONFIGLOCATION="/config"
CONFIGFILEBROWSER="/addon_configs/${HOSTNAME/-/_}/$slug.sh"
else
# Legacy config location
CONFIGLOCATION="/config/addons_autoscripts"
CONFIGFILEBROWSER="/homeassistant/addons_autoscripts/$slug.sh"
fi
# Default location
mkdir -p "$CONFIGLOCATION" || true
CONFIGSOURCE="$CONFIGLOCATION/$slug.sh"
bashio::log.notice "This script is used to run custom commands at start of the addon. Instructions here : https://github.com/alexbelgium/hassio-addons/wiki/Running-custom-scripts-in-Addons"
bashio::log.green "Execute $CONFIGFILEBROWSER if existing"
# Download template if no script found and exit
if [ ! -f "$CONFIGSOURCE" ]; then
TEMPLATESOURCE="https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/.templates/script.template"
curl -f -L -s -S "$TEMPLATESOURCE" --output "$CONFIGSOURCE" || true
exit 0
fi
# Convert scripts to linux
dos2unix "$CONFIGSOURCE" &> /dev/null || true
chmod +x "$CONFIGSOURCE"
# Get current shebang, if not available use another
currentshebang="$(sed -n '1{s/^#![[:blank:]]*//p;q}' "$CONFIGSOURCE")"
if [ ! -f "${currentshebang%% *}" ]; then
for shebang in "/command/with-contenv bashio" "/usr/bin/env bashio" "/usr/bin/bashio" "/bin/bash" "/bin/sh"; do if [ -f "${shebang%% *}" ]; then break; fi; done
sed -i "s|$currentshebang|$shebang|g" "$CONFIGSOURCE"
fi
# Check if there is actual commands
while IFS= read -r line; do
# Remove leading and trailing whitespaces
line="$(echo "$line" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
# Check if line is not empty and does not start with #
if [[ -n "$line" ]] && [[ ! "$line" =~ ^# ]]; then
bashio::log.green "... script found, executing"
/."$CONFIGSOURCE"
break
fi
done < "$CONFIGSOURCE"

View File

@@ -0,0 +1,46 @@
#!/usr/bin/with-contenv bashio
# shellcheck shell=bash
set -e
# shellchek disable=SC2015
JSONTOCHECK='/config/transmission/settings.json'
JSONSOURCE='/defaults/settings.json'
# If json already exists
if [ -f "${JSONTOCHECK}" ]; then
# Variables
echo "Checking settings.json format"
# Check if json file valid or not
jq . -S "${JSONTOCHECK}" &> /dev/null && ERROR=false || ERROR=true
if [ "$ERROR" = true ]; then
bashio::log.fatal "Settings.json structure is abnormal, restoring options from scratch. Your old file is renamed as settings.json_old"
mv "${JSONSOURCE}" "${JSONSOURCE}"_old
cp "${JSONSOURCE}" "${JSONTOCHECK}"
exit 0
fi
# Get the default keys from the original file
mapfile -t arr < <(jq -r 'keys[]' "${JSONSOURCE}")
# Check if all keys are still there, or add them
# spellcheck disable=SC2068
for KEYS in "${arr[@]}"; do
# Check if key exists
KEYSTHERE=$(jq "has(\"${KEYS}\")" "${JSONTOCHECK}")
if [ "$KEYSTHERE" != "true" ]; then
#Fetch initial value
JSONSOURCEVALUE=$(jq -r ".\"$KEYS\"" "${JSONSOURCE}")
#Add key
sed -i "3 i\"${KEYS}\": \"${JSONSOURCEVALUE}\"," "${JSONTOCHECK}"
# Message
bashio::log.warning "${KEYS} was missing from your settings.json, it was added with the default value ${JSONSOURCEVALUE}"
fi
done
# Show structure in a nice way
jq . -S "${JSONTOCHECK}" | cat > temp.json && mv temp.json "${JSONTOCHECK}"
# Message
bashio::log.info "Your settings.json was checked and seems perfectly normal!"
fi

View File

@@ -0,0 +1,35 @@
#!/usr/bin/with-contenv bashio
# shellcheck shell=bash
set -e
# Disables ingress and sets a default index
# Disable Ingress
if bashio::config.true "ingress_disabled"; then
bashio::log.warning "Ingress is disabled. You'll need to connect using ip:port"
# Adapt ingress.conf
sed -i "/root/d" /etc/nginx/servers/ingress.conf
sed -i "/proxy_pass/i root /etc;" /etc/nginx/servers/ingress.conf
sed -i "/proxy_pass/i try_files '' /ingress.html =404;" /etc/nginx/servers/ingress.conf
sed -i "/proxy_pass/d" /etc/nginx/servers/ingress.conf
# Create index.html
touch /etc/ingress.html
cat > /etc/ingress.html << EOF
<!DOCTYPE html>
<html>
<head>
<title>Ingress is disabled!</title>
</head>
<body>
<div class="your_class"></div>
<p style="background-color:black;color:yellow">
Ingress was disabled by the user. Please connect using ip:port or
re-enable in the addons options.
</p>
</body>
</html>
EOF
fi

43
.templates/90-dns_set.sh Normal file
View File

@@ -0,0 +1,43 @@
#!/usr/bin/with-contenv bashio
# shellcheck shell=bash
set -e
###############
# DNS SETTING #
###############
# Avoid usage of local dns such as adguard home or pihole\n"
if bashio::config.has_value 'DNS_server'; then
# Define variables
DNSSERVER=$(bashio::config 'DNS_server')
DNS=""
DNSLIST=""
# Get DNS servers
# shellcheck disable=SC2086
for server in ${DNSSERVER//,/ }; do # Separate comma separated values
# Only add DNS if successful
if ping -c 1 "$server" &> /dev/null; then
DNS="${DNS}nameserver $server\n"
DNSLIST="$server $DNSLIST"
else
bashio::log.warning "DNS $server was requested but can't be pinged. It won't be used"
fi
done
# Only add DNS if there are DNS set
# shellcheck disable=SC2236
if [[ -n "${DNS:-}" ]]; then
# Write resolv.conf
# shellcheck disable=SC2059
printf "${DNS}" > /etc/resolv.conf
chmod 644 /etc/resolv.conf
bashio::log.info "DNS SERVERS set to $DNSLIST"
else
bashio::log.warning "No valid DNS were found. Using default router (or HA) dns servers."
fi
else
bashio::log.info "DNS Servers option empty. Using default router (or HA) dns servers."
fi

14
.templates/91-silent.sh Normal file
View File

@@ -0,0 +1,14 @@
#!/usr/bin/with-contenv bashio
# shellcheck shell=bash
set -e
###############
# SILENT MODE #
###############
if bashio::config.true 'silent'; then
APPEND=' > /dev/null'
sed -i '$s|$|'"$APPEND"'|' /etc/services.d/*/run &> /dev/null || true
sed -i '$s|$|'"$APPEND"'|' /etc/cont-init.d/*/*run* &> /dev/null || true
bashio::log.info 'Silent mode activated, all logs from emby server are hidden. Disable this option if you need to troubleshoot the addon.'
fi

View File

@@ -0,0 +1,172 @@
#!/usr/bin/env bashio
set -e
if bashio::config.has_value "graphic_driver"; then
# Origin : https://github.com/wumingjieno1/photoprism-test/blob/main/scripts/dist/install-gpu.sh
# abort if not executed as root
if [[ $(id -u) != "0" ]]; then
# shellcheck disable=SC2128
bashio::log.fatal "Error: Run $(basename "${BASH_SOURCE}") as root" 1>&2
exit 1
fi
# Get installer type
if [ -f /usr/bin/apt ]; then
bashio::log.info "... Distribution detected : Debian/Ubuntu"
apt-get install -yqq software-properties-common > /dev/null
add-apt-repository ppa:kisak/kisak-mesa > /dev/null
apt-get update > /dev/null
apt-get install -yqq mesa
elif [ -f /usr/bin/apk ]; then
bashio::log.info "... Distribution detected : Alpine"
fi
# Detect GPU
# shellcheck disable=SC2207
GPU_DETECTED=($(lshw -c display -json 2> /dev/null | jq -r '.[].configuration.driver'))
bashio::log.info "... GPU detected: ${GPU_DETECTED[*]}"
graphic_driver=""
# Get arch type
BUILD_ARCH="$(uname -m)"
case "$BUILD_ARCH" in
amd64 | AMD64 | x86_64 | x86-64)
BUILD_ARCH=amd64
;;
arm64 | ARM64 | aarch64)
BUILD_ARCH=arm64
graphic_driver=aarch64_rpi
;;
arm | ARM | aarch | armv7l | armhf)
bashio::log.fatal "Unsupported Machine Architecture: $BUILD_ARCH" 1>&2
exit 1
;;
*)
bashio::log.fatal "Unsupported Machine Architecture: $BUILD_ARCH" 1>&2
exit 1
;;
esac
bashio::log.info "... architecture detected: ${BUILD_ARCH}"
#graphic_driver="$(bashio::config "graphic_driver")"
case "$graphic_driver" in
x64_AMD)
if [[ "$BUILD_ARCH" != amd64 ]]; then bashio::log.fatal "Wrong architecture, $graphic_driver doesn't support $BUILD_ARCH"; fi
[ -f /usr/bin/apt ] && DOCKER_MODS=linuxserver/mods:jellyfin-amd && run_mods > /dev/null && bashio::log.green "... done"
[ -f /usr/bin/apk ] && apk add --no-cache mesa-dri-classic mesa-vdpau-gallium linux-firmware-radeon > /dev/null && bashio::log.green "... done"
;;
x64_NVIDIA)
if [[ "$BUILD_ARCH" != amd64 ]]; then bashio::log.fatal "Wrong architecture, $graphic_driver doesn't support $BUILD_ARCH"; fi
[ -f /usr/bin/apk ] && apk add --no-cache linux-firmware-radeon > /dev/null && bashio::log.green "... done"
[ -f /usr/bin/apt ] && apt-get -yqq install libcuda1 libnvcuvid1 libnvidia-encode1 nvidia-opencl-icd nvidia-vdpau-driver nvidia-driver-libs nvidia-kernel-dkms libva2 vainfo libva-wayland2 > /dev/null && bashio::log.green "... done"
;;
x64_Intel)
if [[ "$BUILD_ARCH" != amd64 ]]; then bashio::log.fatal "Wrong architecture, $graphic_driver doesn't support $BUILD_ARCH"; fi
[ -f /usr/bin/apk ] && apk add --no-cache opencl mesa-dri-gallium mesa-vulkan-intel mesa-dri-intel intel-media-driver > /dev/null && bashio::log.green "... done"
[ -f /usr/bin/apt ] && DOCKER_MODS=linuxserver/mods:jellyfin-opencl-intel && run_mods && apt-get -yqq install intel-opencl-icd intel-media-va-driver-non-free i965-va-driver-shaders mesa-va-drivers libmfx1 libva2 vainfo libva-wayland2 > /dev/null && bashio::log.green "... done"
;;
aarch64_rpi)
if [[ "$BUILD_ARCH" != arm64 ]]; then bashio::log.fatal "Wrong architecture, $graphic_driver doesn't support $BUILD_ARCH"; fi
bashio::log.info "Installing Rpi graphic drivers"
[ -f /usr/bin/apk ] && apk add --no-cache mesa-dri-vc4 mesa-dri-swrast mesa-gbm xf86-video-fbdev > /dev/null && bashio::log.green "... done"
[ -f /usr/bin/apt ] && apt-get -yqq install libgles2-mesa libgles2-mesa-dev xorg-dev > /dev/null && bashio::log.green "... done"
;;
esac
# Main run logic
run_mods() {
echo "[mod-init] Attempting to run Docker Modification Logic"
for DOCKER_MOD in $(echo "${DOCKER_MODS}" | tr '|' '\n'); do
# Support alternative endpoints
if [[ ${DOCKER_MOD} == ghcr.io/* ]] || [[ ${DOCKER_MOD} == linuxserver/* ]]; then
DOCKER_MOD="${DOCKER_MOD#ghcr.io/*}"
ENDPOINT="${DOCKER_MOD%%:*}"
USERNAME="${DOCKER_MOD%%/*}"
REPO="${ENDPOINT#*/}"
TAG="${DOCKER_MOD#*:}"
if [[ ${TAG} == "${DOCKER_MOD}" ]]; then
TAG="latest"
fi
FILENAME="${USERNAME}.${REPO}.${TAG}"
AUTH_URL="https://ghcr.io/token?scope=repository%3A${USERNAME}%2F${REPO}%3Apull"
MANIFEST_URL="https://ghcr.io/v2/${ENDPOINT}/manifests/${TAG}"
BLOB_URL="https://ghcr.io/v2/${ENDPOINT}/blobs/"
MODE="ghcr"
else
ENDPOINT="${DOCKER_MOD%%:*}"
USERNAME="${DOCKER_MOD%%/*}"
REPO="${ENDPOINT#*/}"
TAG="${DOCKER_MOD#*:}"
if [[ ${TAG} == "${DOCKER_MOD}" ]]; then
TAG="latest"
fi
FILENAME="${USERNAME}.${REPO}.${TAG}"
AUTH_URL="https://auth.docker.io/token?service=registry.docker.io&scope=repository:${ENDPOINT}:pull"
MANIFEST_URL="https://registry-1.docker.io/v2/${ENDPOINT}/manifests/${TAG}"
BLOB_URL="https://registry-1.docker.io/v2/${ENDPOINT}/blobs/"
MODE="dockerhub"
fi
# Kill off modification logic if any of the usernames are banned
for BANNED in $(curl -s https://raw.githubusercontent.com/linuxserver/docker-mods/master/blacklist.txt); do
if [[ "${BANNED,,}" == "${USERNAME,,}" ]]; then
if [[ -z ${RUN_BANNED_MODS+x} ]]; then
echo "[mod-init] ${DOCKER_MOD} is banned from use due to reported abuse aborting mod logic"
return
else
echo "[mod-init] You have chosen to run banned mods ${DOCKER_MOD} will be applied"
fi
fi
done
echo "[mod-init] Applying ${DOCKER_MOD} files to container"
# Get Dockerhub token for api operations
TOKEN="$(
curl -f --retry 10 --retry-max-time 60 --retry-connrefused \
--silent \
--header 'GET' \
"${AUTH_URL}" \
| jq -r '.token'
)"
# Determine first and only layer of image
SHALAYER=$(get_blob_sha "${MODE}" "${TOKEN}" "${MANIFEST_URL}")
# Check if we have allready applied this layer
if [[ -f "/${FILENAME}" ]] && [[ "${SHALAYER}" == "$(cat /"${FILENAME}")" ]]; then
echo "[mod-init] ${DOCKER_MOD} at ${SHALAYER} has been previously applied skipping"
else
# Download and extract layer to /
curl -f --retry 10 --retry-max-time 60 --retry-connrefused \
--silent \
--location \
--request GET \
--header "Authorization: Bearer ${TOKEN}" \
"${BLOB_URL}${SHALAYER}" -o \
/modtarball.tar.xz
mkdir -p /tmp/mod
tar xzf /modtarball.tar.xz -C /tmp/mod
if [[ -d /tmp/mod/etc/s6-overlay ]]; then
if [[ -d /tmp/mod/etc/cont-init.d ]]; then
rm -rf /tmp/mod/etc/cont-init.d
fi
if [[ -d /tmp/mod/etc/services.d ]]; then
rm -rf /tmp/mod/etc/services.d
fi
fi
shopt -s dotglob
cp -R /tmp/mod/* /
shopt -u dotglob
rm -rf /tmp/mod
rm -rf /modtarball.tar.xz
echo "${SHALAYER}" > "/${FILENAME}"
echo "[mod-init] ${DOCKER_MOD} applied to container"
fi
done
}
fi

View File

@@ -0,0 +1,10 @@
#!/usr/bin/with-contenv bashio
# shellcheck shell=bash
set -e
CONFIGSOURCE=$(bashio::config "CONFIG_LOCATION")
CONFIGSOURCE="$(dirname "${CONFIGSOURCE}")"
if [ -f "$CONFIGSOURCE"/script.sh ]; then
"$CONFIGSOURCE"./script.sh
fi

View File

@@ -0,0 +1,444 @@
# /usr/local/lib/bashio-standalone.sh
# shellcheck shell=bash
# Minimal bashio compatibility layer for running Home Assistant add-ons
# as standalone containers (no Supervisor). It overrides common bashio::*
# functions to source config from ENV (and optionally a JSON file).
# Load it conditionally in your entry script when supervisor isn't reachable.
# -------- internals ----------------------------------------------------------
# Whether to emit ANSI colors (disabled if not a TTY)
if [ -t 1 ]; then
_BASHIO_COLOR=1
else
_BASHIO_COLOR=0
fi
_bashio_color() {
# $1=name; returns ANSI sequence or empty
if [ "$_BASHIO_COLOR" != "1" ]; then return 0; fi
case "$1" in
blue) printf '\033[34m' ;;
green) printf '\033[32m' ;;
yellow) printf '\033[33m' ;;
red) printf '\033[31m' ;;
magenta) printf '\033[35m' ;;
reset) printf '\033[0m' ;;
esac
}
_bashio_log() {
# $1=color name, $2...=msg
local c="$1"
shift
local pre
pre="$(_bashio_color "$c")"
local rst
rst="$(_bashio_color reset)"
printf '%s%s%s\n' "$pre" "$*" "$rst"
}
# Optional JSON options source (single flat object or nested).
# Set STANDALONE_OPTIONS_JSON to a path (e.g., /data/options.json).
# If jq is present, keys can be fetched as .key or .nested.key
_bashio_json_get() {
# $1=key (dot.notation). echoes value or empty; returns 0 always
local key="${1:-}"
local file="${STANDALONE_OPTIONS_JSON:-}"
if [ -z "$file" ] || [ ! -f "$file" ] || ! command -v jq > /dev/null 2>&1; then
return 0
fi
# jq -r returns "null" for missing; convert to empty
local val
val="$(jq -er --arg k "$key" '. as $r | getpath(($k|split("."))) // empty' "$file" 2> /dev/null || true)"
[ "$val" = "null" ] && val=""
printf '%s' "$val"
}
# Map a bashio "key" to an env var name.
# Order tried:
# 1) exact as-is
# 2) uppercase exact
# 3) dot->underscore, dash->underscore (upper & lower)
# 4) with prefixes: CFG_, CONFIG_, ADDON_, OPTION_, OPT_
_bashio_env_get() {
# $1=key
local key="${1:-}"
[ -z "$key" ] && return 0
local variants=()
variants+=("$key")
variants+=("$(printf '%s' "$key" | tr '[:lower:]' '[:upper:]')")
variants+=("$(printf '%s' "$key" | tr '.' '_' | tr '-' '_')")
variants+=("$(printf '%s' "$key" | tr '.' '_' | tr '-' '_' | tr '[:lower:]' '[:upper:]')")
local prefixes=(""
"CFG_" "CONFIG_" "ADDON_" "OPTION_" "OPT_")
local v p name
for v in "${variants[@]}"; do
for p in "${prefixes[@]}"; do
name="${p}${v}"
if [ -n "${!name+x}" ]; then
printf '%s' "${!name}"
return 0
fi
done
done
}
# Helper: true/false parsing
_bashio_is_true() {
# $1=value
case "${1:-}" in
1 | true | TRUE | yes | YES | on | On) return 0 ;;
*) return 1 ;;
esac
}
# Net wait using /dev/tcp (POSIX bash) with a timeout
_bashio_tcp_wait() {
# $1=host $2=port $3=timeout(s, default 30)
local host="$1" port="$2" to="${3:-30}"
local start now
start="$(date +%s)"
while :; do
if exec 3<> "/dev/tcp/${host}/${port}" 2> /dev/null; then
exec 3>&- 3<&-
return 0
fi
now="$(date +%s)"
if [ $((now - start)) -ge "$to" ]; then
return 1
fi
sleep 1
done
}
# -------- logs ---------------------------------------------------------------
bashio::log.blue() { _bashio_log blue "$*"; }
bashio::log.green() { _bashio_log green "$*"; }
bashio::log.yellow() { _bashio_log yellow "$*"; }
bashio::log.red() { _bashio_log red "$*"; }
bashio::log.magenta() { _bashio_log magenta "$*"; }
# compatibility aliases often used
bashio::log.info() { bashio::log.blue "$@"; }
bashio::log.warning() { bashio::log.yellow "$@"; }
bashio::log.error() { bashio::log.red "$@"; }
bashio::log.debug() { printf '%s\n' "$*"; }
# -------- supervisor & addon meta -------------------------------------------
# In standalone, "ping" always fails unless forced
bashio::supervisor.ping() {
if _bashio_is_true "${STANDALONE_FORCE_SUPERVISOR_PING:-}"; then
return 0
fi
return 1
}
# Add-on metadata (use env or sensible defaults)
bashio::addon.name() { printf '%s' "${ADDON_NAME:-Standalone container}"; }
bashio::addon.description() { printf '%s' "${ADDON_DESCRIPTION:-Running without Home Assistant Supervisor}"; }
bashio::addon.version() { printf '%s' "${BUILD_VERSION:-1.0}"; }
bashio::addon.version_latest() { printf '%s' "${ADDON_VERSION_LATEST:-${BUILD_VERSION:-1.0}}"; }
bashio::addon.update_available() {
if [ "${ADDON_VERSION_LATEST:-}" != "" ] && [ "${ADDON_VERSION_LATEST:-}" != "${BUILD_VERSION:-}" ]; then
printf '%s' "true"
return 0
fi
printf '%s' "false"
}
bashio::addon.ingress_port() { printf '%s' "${ADDON_INGRESS_PORT:-}"; }
bashio::addon.ingress_entry() { printf '%s' "${ADDON_INGRESS_ENTRY:-}"; }
bashio::addon.ip_address() { printf '%s' "${ADDON_IP_ADDRESS:-}"; }
# Ports:
# - numeric arg "8080" -> env PORT_8080 or ADDON_PORT_8080, falling back to the number
# - non-numeric "WEB_PORT" -> resolve as config/env key
bashio::addon.port() {
local arg="${1:-}"
if [[ "$arg" =~ ^[0-9]+$ ]]; then
local v
v="$(_bashio_env_get "PORT_${arg}")"
[ -z "$v" ] && v="$(_bashio_env_get "ADDON_PORT_${arg}")"
printf '%s' "${v:-$arg}"
else
printf '%s' "$(_bashio_env_get "$arg")"
fi
}
# -------- system info --------------------------------------------------------
bashio::info.operating_system() {
if [ -r /etc/os-release ]; then
. /etc/os-release
printf '%s' "${PRETTY_NAME:-${NAME:-Linux}}"
else
printf '%s' "Linux"
fi
}
bashio::info.arch() { uname -m; }
bashio::info.machine() { uname -m; }
bashio::info.homeassistant() { printf '%s' "standalone"; }
bashio::info.supervisor() { printf '%s' "standalone"; }
# -------- config -------------------------------------------------------------
# Primary getter:
# 1) ENV (several name variants/prefixes)
# 2) JSON file via STANDALONE_OPTIONS_JSON (jq required)
bashio::config() {
local key="${1:-}"
local v
v="$(_bashio_env_get "$key")"
if [ -z "$v" ]; then
v="$(_bashio_json_get "$key")"
fi
printf '%s' "${v:-}"
}
bashio::config.has_value() {
local k="$1"
[ -n "$(bashio::config "$k")" ]
}
bashio::config.true() {
local k="$1"
_bashio_is_true "$(bashio::config "$k")"
}
# Some add-ons call "require.ssl" (noop by default)
bashio::config.require.ssl() { printf '%s' "${REQUIRE_SSL:-true}"; }
# -------- variables & fs helpers --------------------------------------------
bashio::var.true() { _bashio_is_true "${1:-}"; }
bashio::var.has_value() { [ -n "${1:-}" ]; }
bashio::fs.directory_exists() { [ -d "$1" ]; }
# -------- network/services ---------------------------------------------------
# Wait for TCP service: bashio::net.wait_for host port [timeout]
bashio::net.wait_for() {
local host="$1" port="$2" to="${3:-30}"
_bashio_tcp_wait "$host" "$port" "$to"
}
# Discovery stubs; map to common env names, or JSON:
# Usage patterns seen:
# bashio::services "mqtt" "host"
# bashio::services "mysql" "port"
bashio::services() {
local svc="${1:-}" key="${2:-}"
[ -z "$svc" ] && return 0
local upper svc_upper var v
upper="$(printf '%s' "$key" | tr '[:lower:]' '[:upper:]')"
svc_upper="$(printf '%s' "$svc" | tr '[:lower:]' '[:upper:]')"
# Common mappings
case "$svc_upper:$upper" in
MQTT:HOST) var="MQTT_HOST" ;;
MQTT:PORT) var="MQTT_PORT" ;;
MQTT:USERNAME) var="MQTT_USER" ;;
MQTT:PASSWORD) var="MQTT_PASSWORD" ;;
MQTT:TLS) var="MQTT_TLS" ;;
MYSQL:HOST | MARIADB:HOST) var="DB_HOST" ;;
MYSQL:PORT | MARIADB:PORT) var="DB_PORT" ;;
MYSQL:USERNAME | MARIADB:USERNAME) var="DB_USER" ;;
MYSQL:PASSWORD | MARIADB:PASSWORD) var="DB_PASSWORD" ;;
MYSQL:DATABASE | MARIADB:DATABASE) var="DB_NAME" ;;
*) var="${svc_upper}_${upper}" ;;
esac
v="$(_bashio_env_get "$var")"
if [ -z "$v" ] && [ -n "${STANDALONE_OPTIONS_JSON:-}" ]; then
v="$(_bashio_json_get "services.${svc}.${key}")"
[ -z "$v" ] && v="$(_bashio_json_get "${svc}.${key}")"
fi
printf '%s' "${v:-}"
}
# ----- extras for broader compatibility --------------------------------------
# Simple cache (used by add-ons & bashio itself)
_BASHIO_CACHE_DIR="${BASHIO_CACHE_DIR:-/tmp/.bashio}"
mkdir -p "$_BASHIO_CACHE_DIR"
bashio::cache.exists() { [ -f "$_BASHIO_CACHE_DIR/${1}.cache" ]; }
bashio::cache.get() { [ -f "$_BASHIO_CACHE_DIR/${1}.cache" ] && cat "$_BASHIO_CACHE_DIR/${1}.cache"; }
bashio::cache.set() {
mkdir -p "$_BASHIO_CACHE_DIR"
printf '%s' "${2:-}" > "$_BASHIO_CACHE_DIR/${1}.cache"
}
# Filesystem helpers frequently used
bashio::fs.file_exists() { [ -f "$1" ]; }
bashio::fs.directory_exists() { [ -d "$1" ]; } # already defined earlier; keep if present
bashio::fs.file_contains() {
local f="$1" p="$2"
[ -f "$f" ] && grep -q -- "$p" "$f"
}
# jq wrapper (some add-ons call bashio::jq)
bashio::jq() { command -v jq > /dev/null 2>&1 && jq "$@"; }
# env presence (even if empty) used by config.exists
_bashio_env_has() {
local key="$1" p v name
[ -z "$key" ] && return 1
local variants=(
"$key"
"$(printf '%s' "$key" | tr '.' '_')"
"$(printf '%s' "$key" | tr '.' '_' | tr '[:lower:]' '[:upper:]')"
"$(printf '%s' "$key" | tr '[:lower:]' '[:upper:]')"
)
for v in "${variants[@]}"; do
for p in "" "CFG_" "CONFIG_" "ADDON_" "OPTION_" "OPT_"; do
name="${p}${v}"
if [ -n "${!name+x}" ]; then # defined, even if empty
printf '%s' "$name"
return 0
fi
done
done
return 1
}
# config.exists : key is present (env or JSON), even if value is empty
bashio::config.exists() {
local key="$1" file="${STANDALONE_OPTIONS_JSON:-}"
_bashio_env_has "$key" && return 0
if [ -n "$file" ] && command -v jq > /dev/null 2>&1; then
jq -e --arg k "$key" 'haspath(($k|split(".")))' "$file" > /dev/null 2>&1
return $?
fi
return 1
}
# addon.option : write/delete option in JSON when possible; fallback no-op/env
bashio::addon.option() {
local key="$1" value="${2-__BASHIO_UNSET__}" file="${STANDALONE_OPTIONS_JSON:-}"
if [ -n "$file" ] && command -v jq > /dev/null 2>&1; then
local tmp
tmp="$(mktemp)"
if [ "$value" = "__BASHIO_UNSET__" ]; then
jq --arg k "$key" 'delpath(($k|split(".")))' "$file" > "$tmp" && mv "$tmp" "$file"
else
jq --arg k "$key" --arg v "$value" 'setpath(($k|split(".")); $v)' "$file" > "$tmp" && mv "$tmp" "$file"
fi
return 0
fi
# Fallbacks: export as env or treat delete as no-op
if [ "$value" != "__BASHIO_UNSET__" ]; then
export "$(printf '%s' "$key" | tr '.' '_' | tr '-' '_')"="$value"
fi
}
# services.available : check if we can resolve at least a host for the service
bashio::services.available() {
local svc="$1" host
host="$(bashio::services "$svc" "host")"
[ -n "$host" ]
}
# var helpers
bashio::var.false() { ! _bashio_is_true "${1:-}"; }
bashio::var.has_value() { [ -n "${1:-}" ]; } # already present; keep if defined
# exits used by many add-ons
bashio::exit.ok() { exit 0; }
bashio::exit.nok() {
local m="${1:-}"
[ -n "$m" ] && bashio::log.red "$m"
exit 1
}
# core.check : Supervisor does a config check; allow an overridable command
# Set STANDALONE_CORE_CHECK_CMD="hass --script check_config -c /config" to enable
bashio::core.check() {
if [ -n "${STANDALONE_CORE_CHECK_CMD:-}" ]; then
eval "$STANDALONE_CORE_CHECK_CMD"
else
return 0
fi
}
# --- improvements & extra shims ---------------------------------------------
# Respect NO_COLOR and dumb terminals
if [ -n "${NO_COLOR:-}" ] || [ "${TERM:-}" = "dumb" ]; then
_BASHIO_COLOR=0
fi
# net.wait_for: prefer nc if available, fallback to /dev/tcp
_bashio_tcp_wait_nc() {
# $1=host $2=port $3=timeout(s)
command -v nc > /dev/null 2>&1 || return 1
local host="$1" port="$2" to="${3:-30}"
# BusyBox and OpenBSD nc differ; cover both styles
nc -z -w "$to" "$host" "$port" 2> /dev/null || nc -z "$host" "$port" 2> /dev/null
}
bashio::net.wait_for() {
local host="$1" port="$2" to="${3:-30}"
_bashio_tcp_wait_nc "$host" "$port" "$to" && return 0
_bashio_tcp_wait "$host" "$port" "$to"
}
# DNS helper: bashio::dns.host <hostname> -> prints an IP (or empty)
bashio::dns.host() {
local h="${1:-}"
[ -z "$h" ] && return 1
if command -v getent > /dev/null 2>&1; then
getent ahostsv4 "$h" | awk '{print $1; exit}'
else
# fallback: try busybox nslookup
nslookup "$h" 2> /dev/null | awk '/^Address: /{print $2; exit}'
fi
}
# Hostname
bashio::host.hostname() {
command -v hostname > /dev/null 2>&1 && hostname || printf '%s' "${HOSTNAME:-unknown}"
}
# Home Assistant token (no Supervisor; read from env or JSON)
bashio::homeassistant.token() {
local t="${HOMEASSISTANT_TOKEN:-${HASS_TOKEN:-}}"
if [ -z "$t" ] && [ -n "${STANDALONE_OPTIONS_JSON:-}" ] && command -v jq > /dev/null 2>&1; then
t="$(jq -er '.homeassistant.token // empty' "$STANDALONE_OPTIONS_JSON" 2> /dev/null || true)"
fi
printf '%s' "${t:-}"
}
# config.array:
# Accepts CSV ("a,b,c"), space/newline-separated text, or JSON array ["a","b"].
# Prints one item per line (common pattern in add-ons: `mapfile -t arr < <(bashio::config.array key)`).
bashio::config.array() {
local key="${1:-}" raw val
raw="$(bashio::config "$key")"
[ -z "$raw" ] && return 0
# JSON array?
if command -v jq > /dev/null 2>&1 && printf '%s' "$raw" | jq -e . > /dev/null 2>&1; then
printf '%s' "$raw" | jq -r '.[]' 2> /dev/null && return 0
fi
# CSV -> newline
if printf '%s' "$raw" | grep -q ','; then
printf '%s' "$raw" | tr ',' '\n'
return 0
fi
# Already space/newline-separated
printf '%s\n' "$raw"
}
# Optional: common require.* shims (treat as advisory in standalone)
bashio::config.require.username() { :; }
bashio::config.require.password() { :; }
bashio::config.require.port() { :; }
# -------- end ----------------------------------------------------------------

View File

@@ -0,0 +1,14 @@
#============================#
# ALEXBELGIUM'S ENV INJECTOR #
#============================#
#
# All env variables set in this file will be enabled in the app
# This allows enabling more options that normally available in the addon options
# This file must be filled according to the yaml format.
# If the format is invalid, the addon will note an error.
# To validate your yaml, you can use the free online tool http://www.yamllint.com/
# You can use env both for the addon, and for bashio. For bashio, use BASHIO_LOG_LEVEL instead of LOG_LEVEL
# EXAMPLE of the format (you need to remove the # for it to become active)
# TZ: Europe/Paris

28
.templates/ha_autoapps.sh Normal file
View File

@@ -0,0 +1,28 @@
#!/bin/sh
# shellcheck disable=SC2015
set -e
##############################
# Automatic apps download #
##############################
PACKAGES="$1"
echo "To install : $PACKAGES"
# Install bash if needed
if ! command -v bash > /dev/null 2> /dev/null; then
(apt-get update && apt-get install -yqq --no-install-recommends bash || apk add --no-cache bash) > /dev/null
fi
# Install curl if needed
if ! command -v curl > /dev/null 2> /dev/null; then
(apt-get update && apt-get install -yqq --no-install-recommends curl || apk add --no-cache curl) > /dev/null
fi
# Call apps installer script if needed
curl -f -L -S "https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/.templates/ha_automatic_packages.sh" --output /ha_automatic_packages.sh
chmod 755 /ha_automatic_packages.sh
eval /./ha_automatic_packages.sh "${PACKAGES:-}"
# Clean
rm /ha_automatic_packages.sh

View File

@@ -0,0 +1,283 @@
#!/bin/bash
set -e
########
# INIT #
########
#Verbose or not
VERBOSE=false
#Avoid fails on non declared variables
set +u 2> /dev/null || true
#If no packages, empty
PACKAGES="${*:-}"
#Avoids messages if non interactive
(echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections) &> /dev/null || true
[ "$VERBOSE" = true ] && echo "ENV : $PACKAGES"
############################
# CHECK WHICH BASE IS USED #
############################
if command -v "apk" &> /dev/null; then
# If apk based
[ "$VERBOSE" = true ] && echo "apk based"
PACKMANAGER="apk"
elif command -v "apt" &> /dev/null; then
# If apt-get based
[ "$VERBOSE" = true ] && echo "apt based"
PACKMANAGER="apt"
elif command -v "pacman" &> /dev/null; then
# If apt-get based
[ "$VERBOSE" = true ] && echo "pacman based"
PACKMANAGER="pacman"
fi
###################
# DEFINE PACKAGES #
###################
# ADD GENERAL ELEMENTS
######################
PACKAGES="$PACKAGES jq curl ca-certificates"
# FOR EACH SCRIPT, SELECT PACKAGES
##################################
# Scripts
for files in "/etc/cont-init.d" "/etc/services.d"; do
# Next directory if does not exists
if ! ls $files 1> /dev/null 2>&1; then continue; fi
# Test each possible command
COMMAND="nginx"
if grep -q -rnw "$files/" -e "$COMMAND" && ! command -v $COMMAND &> /dev/null; then
[ "$VERBOSE" = true ] && echo "$COMMAND required"
[ "$PACKMANAGER" = "apk" ] && PACKAGES="$PACKAGES nginx"
[ "$PACKMANAGER" = "apt" ] && PACKAGES="$PACKAGES nginx"
[ "$PACKMANAGER" = "pacman" ] && PACKAGES="$PACKAGES nginx"
if ls /etc/nginx 1> /dev/null 2>&1; then mv /etc/nginx /etc/nginx2; fi
fi
COMMAND="mount"
if grep -q -rnw "$files/" -e "$COMMAND"; then
[ "$VERBOSE" = true ] && echo "$COMMAND required"
[ "$PACKMANAGER" = "apk" ] && PACKAGES="$PACKAGES exfatprogs ntfs-3g ntfs-3g-progs squashfs-tools fuse lsblk"
[ "$PACKMANAGER" = "apt" ] && PACKAGES="$PACKAGES exfat* ntfs* squashfs-tools util-linux"
#[ "$PACKMANAGER" = "pacman" ] && PACKAGES="$PACKAGES ntfs-3g"
fi
COMMAND="ping"
if grep -q -rnw "$files/" -e "$COMMAND" && ! command -v $COMMAND &> /dev/null; then
[ "$VERBOSE" = true ] && echo "$COMMAND required"
[ "$PACKMANAGER" = "apk" ] && PACKAGES="$PACKAGES iputils"
[ "$PACKMANAGER" = "apt" ] && PACKAGES="$PACKAGES iputils-ping"
#[ "$PACKMANAGER" = "pacman" ] && PACKAGES="$PACKAGES iputils"
fi
COMMAND="nmap"
if grep -q -rnw "$files/" -e "$COMMAND"; then
[ "$VERBOSE" = true ] && echo "$COMMAND required"
[ "$PACKMANAGER" = "apk" ] && PACKAGES="$PACKAGES nmap nmap-scripts"
[ "$PACKMANAGER" = "apt" ] && PACKAGES="$PACKAGES nmap"
#[ "$PACKMANAGER" = "pacman" ] && PACKAGES="$PACKAGES iputils"
fi
COMMAND="cifs"
if grep -q -rnw "$files/" -e "$COMMAND"; then
[ "$VERBOSE" = true ] && echo "$COMMAND required"
[ "$PACKMANAGER" = "apk" ] && PACKAGES="$PACKAGES cifs-utils keyutils"
[ "$PACKMANAGER" = "apt" ] && PACKAGES="$PACKAGES cifs-utils keyutils"
[ "$PACKMANAGER" = "pacman" ] && PACKAGES="$PACKAGES cifs-utils keyutils"
fi
COMMAND="nfs"
if grep -q -rnw "$files/" -e "$COMMAND"; then
[ "$VERBOSE" = true ] && echo "$COMMAND required"
[ "$PACKMANAGER" = "apk" ] && PACKAGES="$PACKAGES nfs-utils"
[ "$PACKMANAGER" = "apt" ] && PACKAGES="$PACKAGES nfs-common"
[ "$PACKMANAGER" = "pacman" ] && PACKAGES="$PACKAGES nfs-utils"
fi
COMMAND="smbclient"
if grep -q -rnw "$files/" -e "$COMMAND" && ! command -v $COMMAND &> /dev/null; then
[ "$VERBOSE" = true ] && echo "$COMMAND required"
[ "$PACKMANAGER" = "apk" ] && PACKAGES="$PACKAGES samba samba-client ntfs-3g"
[ "$PACKMANAGER" = "apt" ] && PACKAGES="$PACKAGES samba smbclient ntfs-3g"
[ "$PACKMANAGER" = "pacman" ] && PACKAGES="$PACKAGES samba smbclient"
fi
COMMAND="dos2unix"
if grep -q -rnw "$files/" -e "$COMMAND" && ! command -v $COMMAND &> /dev/null; then
[ "$VERBOSE" = true ] && echo "$COMMAND required"
[ "$PACKMANAGER" = "apk" ] && PACKAGES="$PACKAGES dos2unix"
[ "$PACKMANAGER" = "apt" ] && PACKAGES="$PACKAGES dos2unix"
[ "$PACKMANAGER" = "pacman" ] && PACKAGES="$PACKAGES dos2unix"
fi
COMMAND="openvpn"
if grep -q -rnw "$files/" -e "$COMMAND" && ! command -v $COMMAND &> /dev/null; then
[ "$VERBOSE" = true ] && echo "$COMMAND required"
[ "$PACKMANAGER" = "apk" ] && PACKAGES="$PACKAGES coreutils openvpn"
[ "$PACKMANAGER" = "apt" ] && PACKAGES="$PACKAGES coreutils openvpn"
[ "$PACKMANAGER" = "pacman" ] && PACKAGES="$PACKAGES coreutils openvpn"
fi
COMMAND="jq"
if grep -q -rnw "$files/" -e "$COMMAND" && ! command -v $COMMAND &> /dev/null; then
[ "$VERBOSE" = true ] && echo "$COMMAND required"
[ "$PACKMANAGER" = "apk" ] && PACKAGES="$PACKAGES jq"
[ "$PACKMANAGER" = "apt" ] && PACKAGES="$PACKAGES jq"
[ "$PACKMANAGER" = "pacman" ] && PACKAGES="$PACKAGES jq"
fi
COMMAND="yamllint"
if grep -q -rnw "$files/" -e "$COMMAND" && ! command -v $COMMAND &> /dev/null; then
[ "$VERBOSE" = true ] && echo "$COMMAND required"
[ "$PACKMANAGER" = "apk" ] && PACKAGES="$PACKAGES yamllint"
[ "$PACKMANAGER" = "apt" ] && PACKAGES="$PACKAGES yamllint"
[ "$PACKMANAGER" = "pacman" ] && PACKAGES="$PACKAGES yamllint"
fi
COMMAND="git"
if grep -q -rnw "$files/" -e "$COMMAND" && ! command -v $COMMAND &> /dev/null; then
[ "$VERBOSE" = true ] && echo "$COMMAND required"
[ "$PACKMANAGER" = "apk" ] && PACKAGES="$PACKAGES git"
[ "$PACKMANAGER" = "apt" ] && PACKAGES="$PACKAGES git"
[ "$PACKMANAGER" = "pacman" ] && PACKAGES="$PACKAGES git"
fi
COMMAND="sponge"
if grep -q -rnw "$files/" -e "$COMMAND" && ! command -v $COMMAND &> /dev/null; then
[ "$VERBOSE" = true ] && echo "$COMMAND required"
[ "$PACKMANAGER" = "apk" ] && PACKAGES="$PACKAGES moreutils"
[ "$PACKMANAGER" = "apt" ] && PACKAGES="$PACKAGES moreutils"
[ "$PACKMANAGER" = "pacman " ] && PACKAGES="$PACKAGES moreutils"
fi
COMMAND="sqlite3"
if grep -q -rnw "$files/" -e "$COMMAND" && ! command -v $COMMAND &> /dev/null; then
[ "$VERBOSE" = true ] && echo "$COMMAND required"
[ "$PACKMANAGER" = "apk" ] && PACKAGES="$PACKAGES sqlite"
[ "$PACKMANAGER" = "apt" ] && PACKAGES="$PACKAGES sqlite3"
[ "$PACKMANAGER" = "pacman" ] && PACKAGES="$PACKAGES sqlite3"
fi
COMMAND="pip"
if grep -q -rnw "$files/" -e "$COMMAND" && ! command -v $COMMAND &> /dev/null; then
[ "$VERBOSE" = true ] && echo "$COMMAND required"
[ "$PACKMANAGER" = "apk" ] && PACKAGES="$PACKAGES py3-pip"
[ "$PACKMANAGER" = "apt" ] && PACKAGES="$PACKAGES pip"
[ "$PACKMANAGER" = "pacman" ] && PACKAGES="$PACKAGES pip"
fi
COMMAND="wget"
if grep -q -rnw "$files/" -e "$COMMAND" && ! command -v $COMMAND &> /dev/null; then
[ "$VERBOSE" = true ] && echo "$COMMAND required"
[ "$PACKMANAGER" = "apk" ] && PACKAGES="$PACKAGES wget"
[ "$PACKMANAGER" = "apt" ] && PACKAGES="$PACKAGES wget"
[ "$PACKMANAGER" = "wget" ] && PACKAGES="$PACKAGES wget"
fi
done
####################
# INSTALL ELEMENTS #
####################
# Install apps
[ "$VERBOSE" = true ] && echo "installing packages $PACKAGES"
if [ "$PACKMANAGER" = "apt" ]; then apt-get update > /dev/null; fi
if [ "$PACKMANAGER" = "pacman" ]; then pacman -Sy > /dev/null; fi
# Install apps one by one to allow failures
# shellcheck disable=SC2086
for packagestoinstall in $PACKAGES; do
[ "$VERBOSE" = true ] && echo "... $packagestoinstall"
if [ "$PACKMANAGER" = "apk" ]; then
apk add --no-cache "$packagestoinstall" &> /dev/null || (echo "Error : $packagestoinstall not found" && touch /ERROR)
elif [ "$PACKMANAGER" = "apt" ]; then
apt-get install -yqq --no-install-recommends "$packagestoinstall" &> /dev/null || (echo "Error : $packagestoinstall not found" && touch /ERROR)
elif [ "$PACKMANAGER" = "pacman" ]; then
pacman --noconfirm -S "$packagestoinstall" &> /dev/null || (echo "Error : $packagestoinstall not found" && touch /ERROR)
fi
[ "$VERBOSE" = true ] && echo "... $packagestoinstall done"
done
# Clean after install
[ "$VERBOSE" = true ] && echo "Cleaning apt cache"
if [ "$PACKMANAGER" = "apt" ]; then apt-get clean > /dev/null; fi
# Replace nginx if installed
if ls /etc/nginx2 1> /dev/null 2>&1; then
[ "$VERBOSE" = true ] && echo "replace nginx2"
rm -r /etc/nginx
mv /etc/nginx2 /etc/nginx
mkdir -p /var/log/nginx
touch /var/log/nginx/error.log
fi
#######################
# INSTALL MANUAL APPS #
#######################
# Install micro texteditor
curl https://getmic.ro | bash || true
mv micro /usr/bin || true
micro -plugin install bounce || true
micro -plugin install filemanager || true
for files in "/etc/services.d" "/etc/cont-init.d"; do
# Next directory if does not exists
if ! ls $files 1> /dev/null 2>&1; then continue; fi
# Bashio
if grep -q -rnw "$files/" -e 'bashio' && [ ! -f "/usr/bin/bashio" ]; then
[ "$VERBOSE" = true ] && echo "install bashio"
BASHIO_VERSION="0.14.3"
mkdir -p /tmp/bashio
curl -f -L -s -S "https://github.com/hassio-addons/bashio/archive/v${BASHIO_VERSION}.tar.gz" | tar -xzf - --strip 1 -C /tmp/bashio
mv /tmp/bashio/lib /usr/lib/bashio
ln -s /usr/lib/bashio/bashio /usr/bin/bashio
rm -rf /tmp/bashio
fi
# Lastversion
COMMAND="lastversion"
if grep -q -rnw "$files/" -e "$COMMAND" && ! command -v $COMMAND &> /dev/null; then
[ "$VERBOSE" = true ] && echo "install $COMMAND"
pip install $COMMAND
fi
# Tempio
if grep -q -rnw "$files/" -e 'tempio' && [ ! -f "/usr/bin/tempio" ]; then
[ "$VERBOSE" = true ] && echo "install tempio"
TEMPIO_VERSION="2021.09.0"
BUILD_ARCH="$(bashio::info.arch)"
curl -f -L -f -s -o /usr/bin/tempio "https://github.com/home-assistant/tempio/releases/download/${TEMPIO_VERSION}/tempio_${BUILD_ARCH}"
chmod a+x /usr/bin/tempio
fi
# Mustache
COMMAND="mustache"
if grep -q -rnw "$files/" -e "$COMMAND" && ! command -v $COMMAND &> /dev/null; then
[ "$VERBOSE" = true ] && echo "$COMMAND required"
[ "$PACKMANAGER" = "apk" ] && apk add --no-cache go npm \
&& apk upgrade --no-cache \
&& apk add --no-cache --virtual .build-deps build-base git go \
&& go get -u github.com/quantumew/mustache-cli \
&& cp "$GOPATH"/bin/* /usr/bin/ \
&& rm -rf "$GOPATH" /var/cache/apk/* /tmp/src \
&& apk del .build-deps xz build-base
[ "$PACKMANAGER" = "apt" ] && apt-get update \
&& apt-get install -yqq go npm node-mustache
fi
done
if [ -f /ERROR ]; then
exit 1
fi

View File

@@ -0,0 +1,36 @@
#!/bin/sh
# shellcheck disable=SC2015
set -e
##############################
# Automatic modules download #
##############################
MODULES="$1"
MODULES="$MODULES 00-banner.sh 01-custom_script.sh 01-config_yaml.sh 00-global_var.sh"
echo "To download : $MODULES"
# Install bash if not available
if ! command -v bash > /dev/null 2> /dev/null; then
(apt-get update && apt-get install -yqq --no-install-recommends bash || apk add --no-cache bash) > /dev/null
fi
# Install curl if not available
if ! command -v curl > /dev/null 2> /dev/null; then
(apt-get update && apt-get install -yqq --no-install-recommends curl || apk add --no-cache curl) > /dev/null
fi
# Install ca-certificates if not available
apt-get update && apt-get install -yqq --no-install-recommends ca-certificates || apk add --no-cache ca-certificates > /dev/null || true
# Create folder for scripts
mkdir -p /etc/cont-init.d
# Download scripts
for scripts in $MODULES; do
echo "$scripts" && curl -f -L -s -S "https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/.templates/$scripts" -o /etc/cont-init.d/"$scripts" \
&& [ "$(sed -n '/\/bin/p;q' /etc/cont-init.d/"$scripts")" != "" ] \
|| (echo "script failed to install $scripts" && exit 1)
done
chmod -R 755 /etc/cont-init.d

152
.templates/ha_entrypoint.sh Normal file
View File

@@ -0,0 +1,152 @@
#!/command/with-contenv bashio
# shellcheck shell=bash
# Detect if this is PID1 (main container process) — do this once at the start
PID1=false
if [ "$$" -eq 1 ]; then
PID1=true
echo "Starting as entrypoint"
# Allow s6 commands
if [ -d /command ]; then
ln -sf /command/* /usr/bin/
fi
else
echo "Starting custom scripts"
fi
######################
# Select the shebang #
######################
# List of candidate shebangs, prioritize with-contenv if PID1
candidate_shebangs=()
if $PID1; then
candidate_shebangs+=("/command/with-contenv bashio" "/usr/bin/with-contenv bashio")
fi
candidate_shebangs+=(
"/usr/bin/env bashio"
"/usr/bin/bashio"
"/usr/bin/bash"
"/usr/bin/sh"
"/bin/bash"
"/bin/sh"
)
# Find the first valid shebang interpreter in candidate list
shebang=""
for candidate in "${candidate_shebangs[@]}"; do
command_path="${candidate%% *}"
# Test if command exists and can actually execute a shell command (for shells)
if [ -x "$command_path" ]; then
# Try as both 'sh -c' and 'bashio echo' style
if "$command_path" -c 'echo yes' > /dev/null 2>&1 || "$command_path" echo "yes" > /dev/null 2>&1; then
shebang="$candidate"
break
fi
fi
done
if [ -z "$shebang" ]; then
echo "ERROR: No valid shebang found!"
exit 1
fi
####################
# Starting scripts #
####################
# Loop through /etc/cont-init.d/* scripts and execute them
for SCRIPTS in /etc/cont-init.d/*; do
[ -e "$SCRIPTS" ] || continue
echo "$SCRIPTS: executing"
# Check if run as root (UID 0)
if [ "$(id -u)" -eq 0 ]; then
# Fix permissions for root user
chown "$(id -u)":"$(id -g)" "$SCRIPTS"
chmod a+x "$SCRIPTS"
else
echo -e "\e[38;5;214m$(date) WARNING: Script executed with user $(id -u):$(id -g), things can break and chown won't work\e[0m"
# Disable chown and chmod commands inside the script for non-root users
sed -i "s/^\s*chown /true # chown /g" "$SCRIPTS"
sed -i "s/^\s*chmod /true # chmod /g" "$SCRIPTS"
fi
# Prepare to run
sed -i "1s|^.*|#!$shebang|" "$SCRIPTS"
chmod +x "$SCRIPTS"
# Optionally use 'source' to share env variables, when requested
if [ "${ha_entry_source:-null}" = true ]; then
# Replace exit with return, so sourced scripts can return errors
sed -i -E 's/^\s*exit ([0-9]+)/return \1 \|\| exit \1/g' "$SCRIPTS"
sed -i 's/bashio::exit\.nok/return 1/g' "$SCRIPTS"
sed -i 's/bashio::exit\.ok/return 0/g' "$SCRIPTS"
# shellcheck disable=SC1090
source "$SCRIPTS" || echo -e "\033[0;31mError\033[0m : $SCRIPTS exiting $?"
else
"$SCRIPTS" || echo -e "\033[0;31mError\033[0m : $SCRIPTS exiting $?"
fi
# Cleanup after execution
sed -i '1a echo "Script already ran" && exit 0' "$SCRIPTS"
done
# Start run scripts in services.d and s6-overlay/s6-rc.d if PID1
if $PID1; then
# Run services
shopt -s nullglob
for runfile in /etc/services.d/*/run /etc/s6-overlay/s6-rc.d/*/run; do
[ -f "$runfile" ] || continue
echo "Starting: $runfile"
sed -i "1s|^.*|#!$shebang|" "$runfile"
chmod +x "$runfile"
(exec "$runfile") &
true
done
shopt -u nullglob
fi
######################
# Starting container #
######################
# If this is PID 1, keep alive and manage sigterm for clean shutdown
if $PID1; then
echo " "
echo -e "\033[0;32mEverything started!\033[0m"
terminate() {
echo "Termination signal received, forwarding to subprocesses..."
# Terminate all direct child processes
if command -v pgrep &> /dev/null; then
for pid in $(pgrep -P $$); do
echo "Terminating child PID $pid"
kill -TERM "$pid" 2> /dev/null || echo "Failed to terminate PID $pid"
done
else
# Fallback: Scan /proc for children
for pid in /proc/[0-9]*/; do
pid=${pid#/proc/}
pid=${pid%/}
if [[ "$pid" -ne 1 ]] && grep -q "^PPid:\s*$$" "/proc/$pid/status" 2> /dev/null; then
echo "Terminating child PID $pid"
kill -TERM "$pid" 2> /dev/null || echo "Failed to terminate PID $pid"
fi
done
fi
wait
echo "All subprocesses terminated. Exiting."
exit 0
}
trap terminate SIGTERM SIGINT
# Main keep-alive loop
while :; do
sleep infinity &
wait $!
done
else
echo " "
echo -e "\033[0;32mStarting the upstream container\033[0m"
echo " "
# Launch optional mods script if present
if [ -f /docker-mods ]; then exec /docker-mods; fi
fi

View File

@@ -0,0 +1,62 @@
#!/bin/sh
set -e
##########################################
# Global modifications before entrypoint #
##########################################
# Corrects permissions for s6 v3
################################
PUID="${PUID:-0}"
PGID="${PGID:-0}"
if [ -f /ha_entrypoint.sh ]; then
chown -R "$PUID:$PGID" /ha_entrypoint.sh
chmod -R 755 /ha_entrypoint.sh
fi
if [ -d /etc/cont-init.d ]; then
chown -R "$PUID:$PGID" /etc/cont-init.d
chmod -R 755 /etc/cont-init.d
fi
if [ -d /etc/services.d ]; then
chown -R "$PUID:$PGID" /etc/services.d
chmod -R 755 /etc/services.d
fi
if [ -d /etc/s6-rc.d ]; then
chown -R "$PUID:$PGID" /etc/s6-rc.d
chmod -R 755 /etc/s6-rc.d
fi
# Correct shebang in entrypoint
###############################
# Make s6 contenv if needed
mkdir -p /run/s6/container_environment
# Check if shebang exists
for shebang in "/command/with-contenv bashio" "/usr/bin/env bashio" "/usr/bin/with-contenv bashio" "/usr/bin/bashio" "/usr/bin/bash" "/usr/bin/sh" "/bin/bash" "/bin/sh"; do
command_path="${shebang%% *}"
if [ -x "$command_path" ] && "$command_path" echo "yes" > /dev/null 2>&1; then
echo "Valid shebang: $shebang"
break
fi
done
# Define shebang
sed -i "s|/command/with-contenv bashio|$shebang|g" /ha_entrypoint.sh
# Correct for scripts
for string in "/command/with-contenv bashio" "/usr/bin/with-contenv bashio"; do
grep -sril "$string" /etc/cont-init.d /etc/services.d /etc/s6-overlay/s6-rc.d | while read -r files; do
sed -i "s|$string|$shebang|g" "$files"
done
done
# Avoid interference with LOG_LEVEL used in the app
if [ -f /usr/lib/bashio/bashio.sh ]; then
sed -i 's|{LOG_LEVEL:|{BASHIO_LOG_LEVEL:|g' /usr/lib/bashio/bashio.sh
fi

68
.templates/ha_lsio.sh Normal file
View File

@@ -0,0 +1,68 @@
#!/bin/sh
# shellcheck disable=SC2013,SC2016,SC2236
set -e
#############################
# Modify global lsio images #
#############################
# Set variable
CONFIGLOCATION="${1:-/config}"
echo "Setting config to $CONFIGLOCATION"
# Avoid custom-init.d duplications
for file in $(grep -sril 'Potential tampering with custom' /etc/cont-init.d /etc/services.d /etc/s6-overlay/s6-rc.d); do
rm -f "$file"
done
# If custom config
if [ "$CONFIGLOCATION" != "/config" ]; then
# Create new config folder if needed
for file in $(grep -srl "PUID" /etc/cont-init.d /etc/s6-overlay/s6-rc.d); do
sed -i "1a mkdir -p $CONFIGLOCATION" "$file"
done
# Correct config location
for file in $(grep -Esril "/config[ '\"/]|/config\$" /etc /defaults); do
sed -Ei "s=(/config)+(/| |$|\"|\')=$CONFIGLOCATION\2=g" "$file"
done
fi
# Allow UID and GID setting
for file in $(grep -srl "PUID" /etc/cont-init.d /etc/s6-overlay/s6-rc.d); do
sed -i 's/bash/bashio/g' "$file" && sed -i '1a PUID="$(if bashio::config.has_value "PUID"; then bashio::config "PUID"; else echo "0"; fi)"' "$file"
sed -i '1a PGID="$(if bashio::config.has_value "PGID"; then bashio::config "PGID"; else echo "0"; fi)"' "$file"
done
# Avoid chmod /config if ha config mounted
if [ -f /config/configuration.yaml ] || [ -f /config/configuration.json ]; then
for file in /etc/services.d/*/* /etc/cont-init.d/* /etc/s6-overlay/s6-rc.d/*/*; do
if [ -f "$file" ] && [ -n "$(awk '/chown.*abc:abc.*\\/,/.*\/config( |$)/{print FILENAME}' "$file")" ]; then
sed -i "s|/config$|/data|g" "$file"
fi
done
fi
# Send crond logs to addon logs
if [ -f /etc/s6-overlay/s6-rc.d/svc-cron/run ]; then
sed -i "/exec busybox crond/c exec busybox crond -f -S -L /proc/1/fd/1" /etc/s6-overlay/s6-rc.d/svc-cron/run
sed -i "/exec \/usr\/sbin\/cron/c exec /usr/sbin/cron -f &>/proc/1/fd/1" /etc/s6-overlay/s6-rc.d/svc-cron/run
fi
# variables not found
for file in $(grep -srl "/usr/bin" /etc/cont-init.d /etc/s6-overlay/s6-rc.d); do
sed -i "1a set +u" "$file"
done
# Allow running abc as user 1
sed -i '/usermod/ s/$/ 2>\/dev\/null || true/' /etc/s6-overlay/s6-rc.d/init-adduser/run
sed -i '/groupmod/ s/$/ 2>\/dev\/null || true/' /etc/s6-overlay/s6-rc.d/init-adduser/run
# Replace lsiown if not found
if [ ! -f /usr/bin/lsiown ]; then
for file in $(grep -sril "lsiown" /etc); do
sed -i "s|lsiown|chown|g" "$file"
done
fi

View File

@@ -0,0 +1,9 @@
#!/usr/bin/with-contenv bashio
# shellcheck shell=bash
#################
# CODE INJECTOR #
#################
# Any commands written in this bash script will be executed at addon start
# See guide here : https://github.com/alexbelgium/hassio-addons/wiki/Add%E2%80%90ons-feature-:-customisation

View File

@@ -0,0 +1,9 @@
#Define colors
red=1
green=2
yellow=3
blue=4
violet=5
teal=6
echo "$(tput setaf $red)ENV exported : $word$(tput sgr0)"
echo -e "\033[0;31mError\033[0m : Text"

View File

@@ -4,6 +4,13 @@ FROM $BUILD_FROM
# Add env
ENV LANG C.UTF-8
# Set S6 wait time
ENV S6_CMD_WAIT_FOR_SERVICES=1 \
S6_CMD_WAIT_FOR_SERVICES_MAXTIME=0 \
S6_SERVICES_GRACETIME=0
USER root
# Setup base
RUN \
apk add --no-cache samba \