#!/bin/bash # Define paths CONFIG_PATH="/tmp/rclone.conf" DB_PATH="/tmp/filebrowser.db" DATA_DIR="/data" # Check if RCLONE_CONFIG_DATA secret is set if [ -z "$RCLONE_CONFIG_DATA" ]; then echo "RCLONE_CONFIG_DATA is missing. Starting setup guide server on port 7860..." # Start a simple python server to show the configuration guide python3 -m http.server 7860 --directory /home/user/setup_guide exit 0 fi # Write the rclone config file echo "$RCLONE_CONFIG_DATA" > "$CONFIG_PATH" chmod 600 "$CONFIG_PATH" # Extract the remote name dynamically using Python (robust against newlines and spaces) REMOTE_NAME=$(python3 -c " import configparser config = configparser.ConfigParser() try: config.read('$CONFIG_PATH') sections = config.sections() if sections: print(sections[0].strip()) else: print('') except Exception: print('') ") if [ -z "$REMOTE_NAME" ]; then echo "Failed to parse remote name from rclone config. Using fallback 'gdrive'." REMOTE_NAME="gdrive" fi # Determine the remote path (root or subfolder) to prevent exceeding Hugging Face's 50GB limit if [ -n "$RCLONE_REMOTE_PATH" ]; then # Trim leading/trailing slashes CLEAN_PATH=$(echo "$RCLONE_REMOTE_PATH" | sed -e 's/^\///' -e 's/\/$//') REMOTE_PATH="$REMOTE_NAME:$CLEAN_PATH" echo "Using subfolder path: $REMOTE_PATH" else REMOTE_PATH="$REMOTE_NAME:" echo "Using root path: $REMOTE_PATH" fi # Set shared-with-me flag if requested SHARED_FLAG="" if [ "$RCLONE_SHARED_WITH_ME" = "true" ]; then SHARED_FLAG="--drive-shared-with-me" echo "Rclone will access 'Shared with me' files/folders." fi # Ensure SQLite database file exists so inotifywait can monitor it touch "$DB_PATH" # 1. Download database from Google Drive if it exists echo "Checking for persistent database on Google Drive..." rclone copyto "$REMOTE_PATH/.filebrowser.db" "$DB_PATH" --config "$CONFIG_PATH" --drive-skip-shortcuts --drive-acknowledge-abuse $SHARED_FLAG || true # Initialize config if export fails (e.g. database doesn't exist or is empty) if ! filebrowser config export -d "$DB_PATH" >/dev/null 2>&1; then echo "Initializing database..." filebrowser config init -d "$DB_PATH" filebrowser config set --root "$DATA_DIR" -d "$DB_PATH" fi # Enable Command Runner (shell execution) globally echo "Enabling Command Runner globally..." filebrowser config set --disable-exec=false --commands "zip,unzip,wget,curl,ls" -d "$DB_PATH" # Configure admin password and execution permissions via FILEBROWSER_PASSWORD secret if set if [ -n "$FILEBROWSER_PASSWORD" ]; then echo "FILEBROWSER_PASSWORD secret is set. Configuring admin password..." # Set or update the admin user password and execution permissions echo "Setting admin user password..." if filebrowser users update admin --password "$FILEBROWSER_PASSWORD" --commands "zip,unzip,wget,curl,ls" --perm.execute=true -d "$DB_PATH" >/dev/null 2>&1; then echo "Admin password and permissions updated successfully." else echo "Admin user not found. Creating admin user with custom password..." filebrowser users add admin "$FILEBROWSER_PASSWORD" --perm.admin --perm.execute=true --commands "zip,unzip,wget,curl,ls" -d "$DB_PATH" fi else # Even if password secret is not set, ensure default admin has execute permissions echo "Updating default admin user commands and permissions..." filebrowser users update admin --commands "zip,unzip,wget,curl,ls" --perm.execute=true -d "$DB_PATH" || true fi # 2. Download files from Google Drive to local /data directory echo "Syncing files from Google Drive..." rclone copy "$REMOTE_PATH" "$DATA_DIR" --config "$CONFIG_PATH" --drive-skip-shortcuts --drive-acknowledge-abuse $SHARED_FLAG || true # 3. Start background sync loops # Loop A: Sync files in /data to Google Drive when modified (Debounced & Robust) ( echo "Starting file sync daemon..." LAST_EVENT_FILE="/tmp/last_event_time" PENDING_FILE="/tmp/sync_pending" DEBOUNCE_SECS=10 # Clear any old state rm -f "$LAST_EVENT_FILE" "$PENDING_FILE" # Start inotifywait in monitor mode to ensure we don't miss any events while syncing inotifywait -r -m -e close_write,delete,move "$DATA_DIR" 2>/dev/null | while read -r _; do date +%s > "$LAST_EVENT_FILE" if [ ! -f "$PENDING_FILE" ]; then touch "$PENDING_FILE" fi done & # Background runner that waits for a quiet period before syncing while true; do if [ -f "$PENDING_FILE" ]; then last_time=$(cat "$LAST_EVENT_FILE" 2>/dev/null || echo 0) now=$(date +%s) elapsed=$((now - last_time)) if [ "$elapsed" -ge "$DEBOUNCE_SECS" ]; then rm -f "$PENDING_FILE" echo "Changes detected in $DATA_DIR, syncing to Google Drive ($REMOTE_PATH)..." if rclone copy "$DATA_DIR" "$REMOTE_PATH" --config "$CONFIG_PATH" --drive-skip-shortcuts --drive-acknowledge-abuse $SHARED_FLAG; then echo "File sync successful." else echo "File sync failed or partially completed (e.g. active uploads). Will retry..." # Set last event to now to debounce the next retry date +%s > "$LAST_EVENT_FILE" touch "$PENDING_FILE" fi fi fi sleep 2 done ) & # Loop B: Sync database /tmp/filebrowser.db to Google Drive when modified (Debounced & Robust) ( echo "Starting database sync daemon..." DB_LAST_EVENT="/tmp/db_last_event" DB_PENDING="/tmp/db_sync_pending" DEBOUNCE_SECS=3 # Clear any old state rm -f "$DB_LAST_EVENT" "$DB_PENDING" # Start inotifywait in monitor mode inotifywait -m -e modify "$DB_PATH" 2>/dev/null | while read -r _; do date +%s > "$DB_LAST_EVENT" if [ ! -f "$DB_PENDING" ]; then touch "$DB_PENDING" fi done & # Background runner for database sync while true; do if [ -f "$DB_PENDING" ]; then last_time=$(cat "$DB_LAST_EVENT" 2>/dev/null || echo 0) now=$(date +%s) elapsed=$((now - last_time)) if [ "$elapsed" -ge "$DEBOUNCE_SECS" ]; then rm -f "$DB_PENDING" echo "Database modified, uploading to Google Drive ($REMOTE_PATH)..." if rclone copyto "$DB_PATH" "$REMOTE_PATH/.filebrowser.db" --config "$CONFIG_PATH" $SHARED_FLAG; then echo "Database sync successful." else echo "Database sync failed. Will retry..." date +%s > "$DB_LAST_EVENT" touch "$DB_PENDING" fi fi fi sleep 1 done ) & # 4. Start File Browser echo "Starting File Browser on port 7860..." filebrowser --port 7860 --address 0.0.0.0 --database "$DB_PATH" --root "$DATA_DIR"