Compare commits

..

3 Commits

Author SHA1 Message Date
CanbiZ (MickLesk) 42a1a57587 Fix source line for build.func in obsidian-livesync.sh
Updated the source line to always fetch build.func from the specified URL.
2026-08-03 14:02:09 +02:00
CanbiZ (MickLesk) 16d2e3717b Update ct/obsidian-livesync.sh
Co-authored-by: Sam Heinz <sam@samheinz.com>
2026-08-03 14:01:28 +02:00
push-app-to-main[bot] 18fb43be11 Add obsidian-livesync (ct) 2026-08-03 11:18:35 +00:00
10 changed files with 184 additions and 27 deletions
-6
View File
@@ -526,12 +526,6 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
- fix restore env in split pro [@johanngrobe](https://github.com/johanngrobe) ([#16228](https://github.com/community-scripts/ProxmoxVE/pull/16228))
### 💾 Core
- #### 🔧 Refactor
- core: read all interactive prompts from /dev/tty, drain leftover input on read failure (hotfix) [@MickLesk](https://github.com/MickLesk) ([#16235](https://github.com/community-scripts/ProxmoxVE/pull/16235))
## 2026-08-02
### 🆕 New Scripts
+6
View File
@@ -0,0 +1,6 @@
____ __ _ ___ __ _ _____
/ __ \/ /_ _____(_)___/ (_)___ _____ / / (_) _____ / ___/__ ______ _____
/ / / / __ \/ ___/ / __ / / __ `/ __ \______/ / / / | / / _ \\__ \/ / / / __ \/ ___/
/ /_/ / /_/ (__ ) / /_/ / / /_/ / / / /_____/ /___/ /| |/ / __/__/ / /_/ / / / / /__
\____/_.___/____/_/\__,_/_/\__,_/_/ /_/ /_____/_/ |___/\___/____/\__, /_/ /_/\___/
/____/
+61
View File
@@ -0,0 +1,61 @@
#!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
# Copyright (c) 2021-2026 community-scripts ORG
# Author: MickLesk (CanbiZ)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/vrtmrz/obsidian-livesync | https://couchdb.apache.org/
APP="Obsidian-LiveSync"
var_tags="${var_tags:-documents;notes}"
var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-1024}"
var_disk="${var_disk:-8}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}"
header_info "$APP"
variables
color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if [[ ! -f /opt/couchdb/etc/local.d/obsidian-livesync.ini ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
msg_info "Stopping CouchDB"
systemctl stop couchdb
msg_ok "Stopped CouchDB"
create_backup /var/lib/couchdb /opt/couchdb/etc/local.d/obsidian-livesync.ini /opt/obsidian-livesync/.env
msg_info "Updating Container OS"
$STD apt update
$STD apt upgrade -y
msg_ok "Updated Container OS"
systemctl stop couchdb
restore_backup
msg_info "Starting CouchDB"
systemctl start couchdb
msg_ok "Started CouchDB"
msg_ok "Updated successfully!"
exit
}
start
build_container
description
msg_ok "Completed successfully!\n"
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
echo -e "${INFO}${YW}Configure the Self-hosted LiveSync plugin with the credentials in /opt/obsidian-livesync/.env${CL}"
echo -e "${GATEWAY}${BGN}http://${IP}:5984/_utils/${CL}"
+98
View File
@@ -0,0 +1,98 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: MickLesk (CanbiZ)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/vrtmrz/obsidian-livesync | https://couchdb.apache.org/
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
catch_errors
setting_up_container
network_check
update_os
setup_deb822_repo \
"couchdb" \
"https://couchdb.apache.org/repo/keys.asc" \
"https://apache.jfrog.io/artifactory/couchdb-deb/" \
"$(get_os_info codename)" \
"main"
msg_info "Installing CouchDB"
COUCHDB_ADMIN_USER="admin"
COUCHDB_PASSWORD="$(openssl rand -hex 24)"
COUCHDB_COOKIE="$(openssl rand -hex 16)"
cat <<EOF | debconf-set-selections
couchdb couchdb/mode select standalone
couchdb couchdb/mode seen true
couchdb couchdb/bindaddress string 0.0.0.0
couchdb couchdb/bindaddress seen true
couchdb couchdb/cookie string ${COUCHDB_COOKIE}
couchdb couchdb/cookie seen true
couchdb couchdb/adminpass password ${COUCHDB_PASSWORD}
couchdb couchdb/adminpass seen true
couchdb couchdb/adminpass_again password ${COUCHDB_PASSWORD}
couchdb couchdb/adminpass_again seen true
EOF
DEBIAN_FRONTEND=noninteractive $STD apt-get install -y couchdb
cat <<EOF >/root/.couchdb.credentials
COUCHDB_ADMIN_USER="${COUCHDB_ADMIN_USER}"
COUCHDB_ADMIN_PASSWORD="${COUCHDB_PASSWORD}"
COUCHDB_COOKIE="${COUCHDB_COOKIE}"
EOF
msg_ok "Installed CouchDB"
msg_info "Configuring CouchDB"
mkdir -p /opt/couchdb/etc/local.d /opt/obsidian-livesync
cat <<EOF >/opt/couchdb/etc/local.d/obsidian-livesync.ini
[couchdb]
single_node = true
max_document_size = 50000000
[admins]
admin = ${COUCHDB_PASSWORD}
[chttpd]
bind_address = 0.0.0.0
port = 5984
max_http_request_size = 4294967296
[chttpd_auth]
require_valid_user = true
[httpd]
enable_cors = true
WWW-Authenticate = Basic realm="couchdb"
[cors]
credentials = true
origins = app://obsidian.md,capacitor://localhost,http://localhost
headers = accept, authorization, content-type, origin, referer
methods = GET, PUT, POST, HEAD, DELETE
max_age = 3600
EOF
cat <<EOF >/opt/obsidian-livesync/.env
COUCHDB_URL=http://${LOCAL_IP}:5984
COUCHDB_USER=admin
COUCHDB_PASSWORD=${COUCHDB_PASSWORD}
COUCHDB_DATABASE=obsidiannotes
EOF
chmod 600 /opt/obsidian-livesync/.env
msg_ok "Configured CouchDB"
msg_info "Creating LiveSync Database"
systemctl enable -q couchdb
systemctl restart couchdb
for _ in {1..30}; do
curl -fsS -u "admin:${COUCHDB_PASSWORD}" -X PUT http://127.0.0.1:5984/obsidiannotes >/dev/null 2>&1 && break
sleep 1
done
msg_ok "Created LiveSync Database"
motd_ssh
customize
cleanup_lxc
+1 -1
View File
@@ -126,7 +126,7 @@ network_check() {
fi
if [[ $ipv4_connected == false ]]; then
read -r -p "No Internet detected, would you like to continue anyway? <y/N> " prompt </dev/tty
read -r -p "No Internet detected, would you like to continue anyway? <y/N> " prompt
if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then
echo -e "${INFO}${RD}Expect Issues Without Internet${CL}"
else
+1 -2
View File
@@ -3917,7 +3917,7 @@ run_addon_updates() {
name="${a##*/update_}"
printf 'Do you also want to update addon "%s"? (y/N) [60s]: ' "$name"
ans=""
if read -r -t 60 ans </dev/tty; then :; else echo; fi
if read -r -t 60 ans; then :; else echo; fi
case "${ans,,}" in
y | yes)
bash "$a" || msg_warn "Addon update for $name failed (rc=$?)"
@@ -5729,7 +5729,6 @@ EOF
# read itself failed (e.g. broken/closed stdin, I/O error) rather than
# timing out - don't guess and destroy the container on a read we
# couldn't actually capture; keep it since that's the reversible choice.
while read -r -t 0.1 -n 1 _ </dev/tty 2>/dev/null; do :; done
echo ""
msg_error "Could not read your response (stdin error) - keeping container ${CTID} for safety."
msg_error "Remove it manually if not needed: pct destroy ${CTID}"
+7 -7
View File
@@ -754,7 +754,7 @@ msg_info() {
# Pause mode: Wait for Enter after each step
if [[ "${DEV_MODE_PAUSE:-false}" == "true" ]]; then
echo -en "\n${YWB}[PAUSE]${CL} Press Enter to continue..." >&2
read -r </dev/tty
read -r
fi
return
fi
@@ -769,7 +769,7 @@ msg_info() {
if [[ "${DEV_MODE_PAUSE:-false}" == "true" ]]; then
stop_spinner
echo -en "\n${YWB}[PAUSE]${CL} Press Enter to continue..." >&2
read -r </dev/tty
read -r
fi
}
@@ -1217,7 +1217,7 @@ prompt_confirm() {
# Interactive prompt with timeout
echo -en "${YW}${message} ${hint} (auto-${default} in ${timeout}s): ${CL}"
if read -t "$timeout" -r response </dev/tty; then
if read -t "$timeout" -r response; then
# User provided input
response="${response,,}" # lowercase
case "$response" in
@@ -1310,7 +1310,7 @@ prompt_input() {
# Interactive prompt with timeout
echo -en "${YW}${message}${hint} (auto-default in ${timeout}s): ${CL}" >&2
if read -t "$timeout" -r response </dev/tty; then
if read -t "$timeout" -r response; then
# User provided input (or pressed Enter for empty)
if [[ -n "$response" ]]; then
echo "$response"
@@ -1412,7 +1412,7 @@ prompt_input_required() {
echo -en "${YW}${message} (required, timeout ${timeout}s): ${CL}" >&2
if read -t "$timeout" -r response </dev/tty; then
if read -t "$timeout" -r response; then
if [[ -z "$response" ]]; then
echo -e "${YW}This field is required. Please enter a value. (attempt ${attempts}/3)${CL}" >&2
fi
@@ -1507,7 +1507,7 @@ prompt_select() {
echo -en "${YW}Select [1-${num_options}] (auto-select ${default} in ${timeout}s): ${CL}" >&2
local response
if read -t "$timeout" -r response </dev/tty; then
if read -t "$timeout" -r response; then
if [[ -z "$response" ]]; then
# Empty response, use default
echo "${options[$((default - 1))]}"
@@ -1590,7 +1590,7 @@ prompt_password() {
# Interactive prompt with timeout (silent input)
echo -en "${YW}${message}${hint} (timeout ${timeout}s): ${CL}" >&2
if read -t "$timeout" -rs response </dev/tty; then
if read -t "$timeout" -rs response; then
echo "" >&2 # Newline after hidden input
if [[ -n "$response" ]]; then
# Validate minimum length
+1 -2
View File
@@ -499,7 +499,7 @@ error_handler() {
local response=""
local read_rc
read -t 60 -r response </dev/tty
read -t 60 -r response
read_rc=$?
if [[ $read_rc -eq 0 ]]; then
if [[ -z "$response" || "$response" =~ ^[Yy]$ ]]; then
@@ -543,7 +543,6 @@ error_handler() {
# read itself failed (e.g. broken/closed stdin, I/O error) rather than
# timing out - don't guess and destroy the container on a read we
# couldn't actually capture; keep it since that's the reversible choice.
while read -r -t 0.1 -n 1 _ </dev/tty 2>/dev/null; do :; done
echo ""
if declare -f msg_error >/dev/null 2>&1; then
msg_error "Could not read your response (stdin error) - keeping container ${CTID} for safety."
+1 -1
View File
@@ -201,7 +201,7 @@ network_check() {
# If both IPv4 and IPv6 checks fail, prompt the user
if [[ $ipv4_connected == false && $ipv6_connected == false ]]; then
read -r -p "No Internet detected, would you like to continue anyway? <y/N> " prompt </dev/tty
read -r -p "No Internet detected, would you like to continue anyway? <y/N> " prompt
if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then
echo -e "${INFO}${RD}Expect Issues Without Internet${CL}"
else
+8 -8
View File
@@ -1466,7 +1466,7 @@ prompt_for_github_token() {
fi
local reply
read -rp "${TAB}Would you like to enter a GitHub Personal Access Token (PAT)? [y/N]: " reply </dev/tty
read -rp "${TAB}Would you like to enter a GitHub Personal Access Token (PAT)? [y/N]: " reply
reply="${reply:-n}"
if [[ ! "${reply,,}" =~ ^(y|yes)$ ]]; then
@@ -1475,7 +1475,7 @@ prompt_for_github_token() {
local token
while true; do
read -rp "${TAB}Enter your GitHub PAT: " token </dev/tty
read -rp "${TAB}Enter your GitHub PAT: " token
# Trim leading/trailing whitespace
token="$(echo "$token" | xargs)"
if [[ -z "$token" ]]; then
@@ -3973,7 +3973,7 @@ _gh_scan_older_releases() {
local use_fallback="y"
if [[ -t 0 ]]; then
msg_warn "Release ${skip_tag} has no matching asset. Previous release ${rel_tag} has a compatible asset."
read -rp "Use version ${rel_tag} instead? [Y/n] (auto-yes in 60s): " -t 60 use_fallback </dev/tty || use_fallback="y"
read -rp "Use version ${rel_tag} instead? [Y/n] (auto-yes in 60s): " -t 60 use_fallback || use_fallback="y"
use_fallback="${use_fallback:-y}"
fi
@@ -4796,7 +4796,7 @@ EOF
for entry in "${compose_updates[@]}"; do
IFS='|' read -r name image compose_workdir compose_service <<<"$entry"
reply=""
if read -r -t 60 -p "${TAB3}Update ${name} (${image}) via Compose? <y/N> (auto-no in 60s): " reply </dev/tty; then
if read -r -t 60 -p "${TAB3}Update ${name} (${image}) via Compose? <y/N> (auto-no in 60s): " reply; then
echo ""
else
echo ""
@@ -4814,7 +4814,7 @@ EOF
for entry in "${standalone_updates[@]}"; do
IFS='|' read -r name image <<<"$entry"
reply=""
if read -r -t 60 -p "${TAB3}Pull new image for ${name} (${image})? <y/N> (auto-no in 60s): " reply </dev/tty; then
if read -r -t 60 -p "${TAB3}Pull new image for ${name} (${image})? <y/N> (auto-no in 60s): " reply; then
echo ""
else
echo ""
@@ -5409,7 +5409,7 @@ setup_hwaccel() {
# Read with 60 second timeout
local selection=""
echo -n "Select GPU(s) to configure (1-${gpu_count}, A=all) [timeout 60s, default=all]: "
if read -r -t 60 selection </dev/tty; then
if read -r -t 60 selection; then
selection="${selection^^}" # uppercase
else
echo ""
@@ -5457,7 +5457,7 @@ setup_hwaccel() {
echo ""
msg_custom "🎮" "${GN}" "NVIDIA GPU passthrough detected"
local nvidia_reply=""
read -r -t 60 -p "${TAB3}⚙️ Install NVIDIA driver libraries in the container? [Y/n] (auto-yes in 60s): " nvidia_reply </dev/tty || nvidia_reply=""
read -r -t 60 -p "${TAB3}⚙️ Install NVIDIA driver libraries in the container? [Y/n] (auto-yes in 60s): " nvidia_reply || nvidia_reply=""
case "${nvidia_reply,,}" in
n | no) install_nvidia_drivers="no" ;;
*) install_nvidia_drivers="yes" ;;
@@ -9755,7 +9755,7 @@ _gl_scan_older_releases() {
local use_fallback="y"
if [[ -t 0 ]]; then
msg_warn "Release ${skip_tag} has no matching asset. Previous release ${rel_tag} has a compatible asset."
read -rp "Use version ${rel_tag} instead? [Y/n] (auto-yes in 60s): " -t 60 use_fallback </dev/tty || use_fallback="y"
read -rp "Use version ${rel_tag} instead? [Y/n] (auto-yes in 60s): " -t 60 use_fallback || use_fallback="y"
use_fallback="${use_fallback:-y}"
fi