File size: 6,994 Bytes
8ed4d8b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9b5dfdf
 
 
 
 
 
 
 
 
 
 
 
 
 
8ed4d8b
 
 
 
 
 
9f8a082
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8ed4d8b
 
 
 
 
 
9f8a082
8ed4d8b
ca04d92
 
 
 
 
 
 
 
 
 
 
 
f013923
 
ca04d92
a795742
ca04d92
 
a795742
ca04d92
 
f013923
ca04d92
 
 
 
f013923
 
8ed4d8b
 
9f8a082
8ed4d8b
 
002a6d2
8ed4d8b
 
002a6d2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8ed4d8b
002a6d2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8ed4d8b
 
 
002a6d2
8ed4d8b
 
002a6d2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8ed4d8b
002a6d2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8ed4d8b
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#!/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"