Abdelrhman2008 commited on
Commit
dbcbb03
ยท
verified ยท
1 Parent(s): f4ff785

Update sync_data.sh

Browse files
Files changed (1) hide show
  1. sync_data.sh +164 -346
sync_data.sh CHANGED
@@ -1,8 +1,8 @@
1
  #!/bin/bash
2
 
3
  # ========================================
4
- # Open WebUI GitHub Sync - v7 with Auto-Repair
5
- # ู…ุน ุฅุตู„ุงุญ ุชู„ู‚ุงุฆูŠ ู„ู‚ุงุนุฏุฉ ุงู„ุจูŠุงู†ุงุช ุงู„ุชุงู„ูุฉ
6
  # ========================================
7
 
8
  set -eo pipefail
@@ -13,8 +13,7 @@ set -eo pipefail
13
  readonly DB_FILE="/app/backend/data/webui.db"
14
  readonly DATA_DIR="./data"
15
  readonly TEMP_DIR="$DATA_DIR/git_temp"
16
- readonly LOCAL_HASH_FILE="$DATA_DIR/local_hash.txt"
17
- readonly GITHUB_HASH_FILE="$DATA_DIR/github_hash.txt"
18
  readonly BACKUP_DIR="$DATA_DIR/backups"
19
  readonly MAX_BACKUPS=5
20
  readonly SYNC_INTERVAL=3600
@@ -31,467 +30,286 @@ log_warn() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] โš ๏ธ $1"; }
31
  # ุงู„ุชุญู‚ู‚ ู…ู† ุงู„ู…ุชุทู„ุจุงุช
32
  # ========================================
33
  check_requirements() {
34
- log_info "ุงู„ุชุญู‚ู‚ ู…ู† ุงู„ู…ุชุทู„ุจุงุช..."
35
-
36
- if [[ -z "${G_NAME:-}" ]]; then
37
- log_error "G_NAME ุบูŠุฑ ู…ูˆุฌูˆุฏ!"
38
- return 1
39
- fi
40
-
41
- if [[ -z "${G_TOKEN:-}" ]]; then
42
- log_error "G_TOKEN ุบูŠุฑ ู…ูˆุฌูˆุฏ!"
43
  return 1
44
  fi
45
 
46
- mkdir -p "$DATA_DIR" "$BACKUP_DIR"
47
  log_success "ุงู„ู…ุชุทู„ุจุงุช ู…ุชูˆูุฑุฉ | Repo: $G_NAME"
48
  return 0
49
  }
50
 
51
- # ========================================
52
- # ุงู„ุชุญู‚ู‚ ู…ู† Token
53
- # ========================================
54
- verify_token() {
55
- local http_code
56
- http_code=$(curl -s -o /dev/null -w "%{http_code}" \
57
- -H "Authorization: token $G_TOKEN" \
58
- "https://api.github.com/repos/$G_NAME" 2>/dev/null)
59
-
60
- case $http_code in
61
- 200) log_success "Token ุตุญูŠุญ"; return 0 ;;
62
- 404) log_warn "ุงู„ู…ุณุชูˆุฏุน ุบูŠุฑ ู…ูˆุฌูˆุฏ"; return 0 ;;
63
- *) log_error "ุฎุทุฃ Token: $http_code"; return 1 ;;
64
- esac
65
- }
66
-
67
  # ========================================
68
  # ุญุณุงุจ Hash
69
  # ========================================
70
- get_file_hash() {
71
- [[ -f "$1" ]] && [[ -s "$1" ]] && sha256sum "$1" 2>/dev/null | cut -d' ' -f1 || echo "none"
72
  }
73
 
74
  # ========================================
75
- # ุงู„ุชุญู‚ู‚ ู…ู† ุตุญุฉ SQLite
76
  # ========================================
77
  verify_sqlite() {
78
- local db_path="$1"
79
-
80
- [[ ! -f "$db_path" ]] && return 1
81
-
82
- # ูุญุต ุณุฑูŠุน
83
- if ! file "$db_path" 2>/dev/null | grep -q "SQLite"; then
84
- return 1
85
- fi
86
-
87
- # ูุญุต ุงู„ุณู„ุงู…ุฉ
88
- local check_result
89
- check_result=$(sqlite3 "$db_path" "PRAGMA integrity_check;" 2>&1 || echo "error")
90
-
91
- [[ "$check_result" == "ok" ]] && return 0 || return 1
92
  }
93
 
94
  # ========================================
95
- # โญ ุฅุตู„ุงุญ ู‚ุงุนุฏุฉ ุงู„ุจูŠุงู†ุงุช ุงู„ุชุงู„ูุฉ
96
  # ========================================
97
- repair_database() {
98
- local db_path="$1"
99
- local repaired_path="${db_path}.repaired"
100
-
101
- log_warn "๐Ÿ”ง ู…ุญุงูˆู„ุฉ ุฅุตู„ุงุญ ู‚ุงุนุฏุฉ ุงู„ุจูŠุงู†ุงุช..."
102
-
103
- # ุงู„ุทุฑูŠู‚ุฉ 1: ุงุณุชุฎุฏุงู… .recover (SQLite 3.29+)
104
- log_info "ู…ุญุงูˆู„ุฉ 1: ุงุณุชุฎุฏุงู… .recover..."
105
- if sqlite3 "$db_path" ".recover" 2>/dev/null | sqlite3 "$repaired_path" 2>/dev/null; then
106
- if verify_sqlite "$repaired_path"; then
107
- mv "$repaired_path" "$db_path"
108
- log_success "โœ… ุชู… ุงู„ุฅุตู„ุงุญ ุจู€ .recover!"
109
- return 0
110
- fi
111
- fi
112
- rm -f "$repaired_path" 2>/dev/null
113
-
114
- # ุงู„ุทุฑูŠู‚ุฉ 2: dump ูˆ restore
115
- log_info "ู…ุญุงูˆู„ุฉ 2: ุงุณุชุฎุฏุงู… dump..."
116
- if sqlite3 "$db_path" ".dump" 2>/dev/null | sqlite3 "$repaired_path" 2>/dev/null; then
117
- if verify_sqlite "$repaired_path"; then
118
- mv "$repaired_path" "$db_path"
119
- log_success "โœ… ุชู… ุงู„ุฅุตู„ุงุญ ุจู€ dump!"
120
- return 0
121
- fi
122
- fi
123
- rm -f "$repaired_path" 2>/dev/null
124
 
125
- # ุงู„ุทุฑูŠู‚ุฉ 3: ู†ุณุฎ ุงู„ุฌุฏุงูˆู„ ูŠุฏูˆูŠุงู‹
126
- log_info "ู…ุญุงูˆู„ุฉ 3: ู†ุณุฎ ุงู„ุฌุฏุงูˆู„..."
127
- local tables
128
- tables=$(sqlite3 "$db_path" "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%';" 2>/dev/null || echo "")
129
 
130
- if [[ -n "$tables" ]]; then
131
- sqlite3 "$repaired_path" "PRAGMA journal_mode=WAL;" 2>/dev/null
132
-
133
- local success_count=0
134
- local total_count=0
135
-
136
- for table in $tables; do
137
- total_count=$((total_count + 1))
138
-
139
- # ู…ุญุงูˆู„ุฉ ู†ุณุฎ ุงู„ุฌุฏูˆู„
140
- local schema
141
- schema=$(sqlite3 "$db_path" ".schema $table" 2>/dev/null || echo "")
142
-
143
- if [[ -n "$schema" ]]; then
144
- sqlite3 "$repaired_path" "$schema" 2>/dev/null || continue
145
-
146
- # ู†ุณุฎ ุงู„ุจูŠุงู†ุงุช
147
- if sqlite3 "$db_path" "SELECT * FROM $table;" 2>/dev/null | \
148
- sqlite3 "$repaired_path" ".import /dev/stdin $table" 2>/dev/null; then
149
- success_count=$((success_count + 1))
150
- log_info " โœ“ ุชู… ู†ุณุฎ: $table"
151
- else
152
- # ู…ุญุงูˆู„ุฉ ุจุฏูŠู„ุฉ
153
- sqlite3 "$db_path" ".mode insert $table" ".output /tmp/table_$table.sql" "SELECT * FROM $table;" 2>/dev/null
154
- sqlite3 "$repaired_path" < "/tmp/table_$table.sql" 2>/dev/null && success_count=$((success_count + 1))
155
- rm -f "/tmp/table_$table.sql" 2>/dev/null
156
- fi
157
- fi
158
- done
159
-
160
- if [[ $success_count -gt 0 ]] && verify_sqlite "$repaired_path"; then
161
- mv "$repaired_path" "$db_path"
162
- log_success "โœ… ุชู… ุฅุตู„ุงุญ $success_count/$total_count ุฌุฏุงูˆู„!"
163
- return 0
164
- fi
165
- fi
166
- rm -f "$repaired_path" 2>/dev/null
167
-
168
- # ุงู„ุทุฑูŠู‚ุฉ 4: reindex
169
- log_info "ู…ุญุงูˆู„ุฉ 4: ุฅุนุงุฏุฉ ุจู†ุงุก ุงู„ูู‡ุงุฑุณ..."
170
- if sqlite3 "$db_path" "REINDEX;" 2>/dev/null; then
171
- if verify_sqlite "$db_path"; then
172
- log_success "โœ… ุชู… ุงู„ุฅุตู„ุงุญ ุจู€ REINDEX!"
173
- return 0
174
- fi
175
  fi
 
176
 
177
- # ุงู„ุทุฑูŠู‚ุฉ 5: vacuum
178
- log_info "ู…ุญุงูˆู„ุฉ 5: VACUUM..."
179
- cp "$db_path" "$repaired_path" 2>/dev/null
180
- if sqlite3 "$repaired_path" "VACUUM;" 2>/dev/null; then
181
- if verify_sqlite "$repaired_path"; then
182
- mv "$repaired_path" "$db_path"
183
- log_success "โœ… ุชู… ุงู„ุฅุตู„ุงุญ ุจู€ VACUUM!"
184
- return 0
185
- fi
186
  fi
187
- rm -f "$repaired_path" 2>/dev/null
188
 
189
- log_error "โŒ ูุดู„ุช ุฌู…ูŠุน ู…ุญุงูˆู„ุงุช ุงู„ุฅุตู„ุงุญ"
190
  return 1
191
  }
192
 
193
  # ========================================
194
- # โญ ุฏู…ุฌ ู‚ุงุนุฏุชูŠ ุจูŠุงู†ุงุช (ุงู„ู…ุญู„ูŠุฉ + GitHub)
195
  # ========================================
196
- merge_databases() {
197
- local local_db="$1"
198
- local github_db="$2"
199
- local merged_db="${local_db}.merged"
200
-
201
- log_info "๐Ÿ”€ ุฏู…ุฌ ู‚ุงุนุฏุชูŠ ุงู„ุจูŠุงู†ุงุช..."
202
-
203
- # ู†ุณุฎ ุงู„ู…ุญู„ูŠุฉ ูƒุฃุณุงุณ
204
- cp "$local_db" "$merged_db" 2>/dev/null || cp "$github_db" "$merged_db"
205
-
206
- # ุงู„ุฌุฏุงูˆู„ ุงู„ู…ู‡ู…ุฉ ู„ู„ุฏู…ุฌ
207
- local important_tables="user chat message auth config memory tool function model prompt knowledge"
208
-
209
- for table in $important_tables; do
210
- # ุงู„ุชุญู‚ู‚ ู…ู† ูˆุฌูˆุฏ ุงู„ุฌุฏูˆู„ ููŠ ูƒู„ุง ุงู„ู‚ุงุนุฏุชูŠู†
211
- local local_exists=$(sqlite3 "$local_db" "SELECT name FROM sqlite_master WHERE type='table' AND name='$table';" 2>/dev/null)
212
- local github_exists=$(sqlite3 "$github_db" "SELECT name FROM sqlite_master WHERE type='table' AND name='$table';" 2>/dev/null)
213
-
214
- if [[ -n "$github_exists" ]]; then
215
- # ุนุฏุฏ ุงู„ุณุฌู„ุงุช
216
- local local_count=$(sqlite3 "$local_db" "SELECT COUNT(*) FROM $table;" 2>/dev/null || echo "0")
217
- local github_count=$(sqlite3 "$github_db" "SELECT COUNT(*) FROM $table;" 2>/dev/null || echo "0")
218
-
219
- log_info " $table: Local=$local_count | GitHub=$github_count"
220
-
221
- # ุฅุฐุง GitHub ููŠู‡ ุณุฌู„ุงุช ุฃูƒุซุฑุŒ ู†ุฏู…ุฌู‡ุง
222
- if [[ "$github_count" -gt "$local_count" ]]; then
223
- log_info " โ† ุฏู…ุฌ ู…ู† GitHub..."
224
-
225
- # ู…ุญุงูˆู„ุฉ ุงู„ุฏู…ุฌ ู…ุน ุชุฌุงู‡ู„ ุงู„ุชูƒุฑุงุฑุงุช
226
- sqlite3 "$github_db" "SELECT * FROM $table;" 2>/dev/null | while read -r row; do
227
- sqlite3 "$merged_db" "INSERT OR IGNORE INTO $table VALUES ($row);" 2>/dev/null || true
228
- done
229
- fi
230
- fi
231
- done
232
-
233
- if verify_sqlite "$merged_db"; then
234
- mv "$merged_db" "$local_db"
235
- log_success "โœ… ุชู… ุงู„ุฏู…ุฌ ุจู†ุฌุงุญ!"
236
- return 0
237
- fi
238
-
239
- rm -f "$merged_db" 2>/dev/null
240
- log_error "โŒ ูุดู„ ุงู„ุฏู…ุฌ"
241
- return 1
242
  }
243
 
244
  # ========================================
245
  # ู†ุณุฎุฉ ุงุญุชูŠุงุทูŠุฉ
246
  # ========================================
247
- create_backup() {
248
- local prefix="${1:-backup}"
249
- [[ ! -f "$DB_FILE" ]] && return 1
250
-
251
- local backup_file="$BACKUP_DIR/${prefix}_$(date '+%Y%m%d_%H%M%S').db"
252
- cp "$DB_FILE" "$backup_file" 2>/dev/null && log_info "Backup: $(basename "$backup_file")"
253
-
254
  ls -1t "$BACKUP_DIR"/*.db 2>/dev/null | tail -n +$((MAX_BACKUPS + 1)) | xargs rm -f 2>/dev/null || true
255
  }
256
 
257
  # ========================================
258
- # ุชู†ุธูŠู
259
- # ========================================
260
- cleanup_temp() {
261
- rm -rf "$TEMP_DIR" 2>/dev/null || true
262
- }
263
-
264
- # ========================================
265
- # Pull ู…ู† GitHub ู…ุน ุฅุตู„ุงุญ
266
  # ========================================
267
  pull_from_github() {
268
- log_info "โฌ‡๏ธ ูุญุต GitHub..."
269
 
270
- cleanup_temp
271
  mkdir -p "$TEMP_DIR"
272
 
273
  local repo_url="https://${G_TOKEN}@github.com/${G_NAME}.git"
274
 
 
275
  if ! GIT_TERMINAL_PROMPT=0 git clone --depth 1 --quiet "$repo_url" "$TEMP_DIR" 2>/dev/null; then
276
  log_info "ุงู„ู…ุณุชูˆุฏุน ูุงุฑุบ"
277
- cleanup_temp
278
  return 1
279
  fi
280
 
281
- if [[ ! -f "$TEMP_DIR/webui.db" ]]; then
282
- log_info "ู„ุง ูŠูˆุฌุฏ webui.db"
283
- cleanup_temp
 
284
  return 1
285
  fi
286
 
287
  local github_db="$TEMP_DIR/webui.db"
288
- local github_valid=false
289
-
290
- # ูุญุต ู…ู„ู GitHub
291
- if verify_sqlite "$github_db"; then
292
- github_valid=true
293
- log_info "โœ“ ู…ู„ู GitHub ุณู„ูŠู…"
294
- else
295
- log_warn "โš ๏ธ ู…ู„ู GitHub ุชุงู„ู - ู…ุญุงูˆู„ุฉ ุงู„ุฅุตู„ุงุญ..."
296
- if repair_database "$github_db"; then
297
- github_valid=true
298
- fi
299
- fi
300
 
301
- if [[ "$github_valid" != "true" ]]; then
302
- log_error "โŒ ู„ุง ูŠู…ูƒู† ุฅุตู„ุงุญ ู…ู„ู GitHub"
303
- cleanup_temp
304
- return 1
305
  fi
306
 
307
- local github_hash=$(get_file_hash "$github_db")
308
- local local_hash=$(get_file_hash "$DB_FILE")
309
- local saved_github_hash=$(cat "$GITHUB_HASH_FILE" 2>/dev/null || echo "none")
310
 
311
- log_info "GitHub: ${github_hash:0:12}... | Local: ${local_hash:0:12}..."
 
 
312
 
313
- # ุฅุฐุง ุงู„ู…ู„ู ุงู„ู…ุญู„ูŠ ู…ูˆุฌูˆุฏุŒ ู†ุญุงูˆู„ ุงู„ุฏู…ุฌ
314
- if [[ -f "$DB_FILE" ]] && [[ -s "$DB_FILE" ]]; then
315
- # ูุญุต ูˆุฅุตู„ุงุญ ุงู„ู…ุญู„ูŠ ุฃูˆู„ุงู‹
316
- if ! verify_sqlite "$DB_FILE"; then
317
- log_warn "โš ๏ธ ุงู„ู…ู„ู ุงู„ู…ุญู„ูŠ ุชุงู„ู - ู…ุญุงูˆู„ุฉ ุงู„ุฅุตู„ุงุญ..."
318
- create_backup "corrupted"
319
- repair_database "$DB_FILE" || true
320
- fi
321
-
322
- # ุฅุฐุง ูƒู„ุงู‡ู…ุง ู…ุฎุชู„ููŠู†ุŒ ู†ุฏู…ุฌ
323
- if [[ "$github_hash" != "$local_hash" ]] && [[ "$github_hash" != "$saved_github_hash" ]]; then
324
- log_info "๐Ÿ”€ ุฏู…ุฌ ุงู„ุชุญุฏูŠุซุงุช..."
325
- create_backup "before_merge"
326
-
327
- if merge_databases "$DB_FILE" "$github_db"; then
328
- local new_hash=$(get_file_hash "$DB_FILE")
329
- echo "$new_hash" > "$GITHUB_HASH_FILE"
330
- echo "$new_hash" > "$LOCAL_HASH_FILE"
331
- log_success "โฌ‡๏ธ ุชู… ุฏู…ุฌ ุงู„ุจูŠุงู†ุงุช!"
332
- cleanup_temp
333
- return 0
334
- fi
335
- fi
336
- else
337
- # ู„ุง ูŠูˆุฌุฏ ู…ู„ู ู…ุญู„ูŠุŒ ุงุณุชุฎุฏู… GitHub
338
- log_info "๐Ÿ“ฅ ุชุญู…ูŠู„ ู…ู† GitHub..."
339
- mkdir -p "$(dirname "$DB_FILE")"
340
- cp "$github_db" "$DB_FILE"
341
- chmod 666 "$DB_FILE"
342
-
343
- echo "$github_hash" > "$GITHUB_HASH_FILE"
344
- echo "$github_hash" > "$LOCAL_HASH_FILE"
345
-
346
- log_success "โฌ‡๏ธ ุชู… ุงู„ุชุญู…ูŠู„ ($(du -h "$DB_FILE" | cut -f1))"
347
- cleanup_temp
348
- return 0
349
- fi
350
 
351
- log_info "โœ“ ู„ุง ุชูˆุฌุฏ ุชุญุฏูŠุซุงุช"
352
- echo "$github_hash" > "$GITHUB_HASH_FILE"
353
- cleanup_temp
354
- return 2
355
  }
356
 
357
  # ========================================
358
- # Push ุฅู„ู‰ GitHub
359
  # ========================================
360
  push_to_github() {
361
- log_info "โฌ†๏ธ ูุญุต ุงู„ุชุบูŠูŠุฑุงุช..."
362
 
 
363
  if [[ ! -f "$DB_FILE" ]]; then
364
- log_warn "ู„ุง ูŠูˆุฌุฏ ู…ู„ู ู…ุญู„ูŠ"
365
  return 1
366
  fi
367
 
368
- # ูุญุต ูˆุฅุตู„ุงุญ ู‚ุจู„ ุงู„ุฑูุน
369
- if ! verify_sqlite "$DB_FILE"; then
370
- log_warn "โš ๏ธ ุงู„ู…ู„ู ุชุงู„ู - ู…ุญุงูˆู„ุฉ ุงู„ุฅุตู„ุงุญ ู‚ุจู„ ุงู„ุฑูุน..."
371
- create_backup "before_repair"
372
- if ! repair_database "$DB_FILE"; then
373
- log_error "โŒ ู„ุง ูŠู…ูƒู† ุฅุตู„ุงุญ ุงู„ู…ู„ู"
374
- return 1
375
- fi
376
- fi
377
 
378
- local current_hash=$(get_file_hash "$DB_FILE")
379
- local last_pushed=$(cat "$LOCAL_HASH_FILE" 2>/dev/null || echo "none")
380
-
381
- if [[ "$current_hash" == "$last_pushed" ]]; then
382
- log_info "โœ“ ู„ุง ุชุบูŠูŠุฑุงุช"
383
  return 0
384
  fi
385
 
386
- log_info "๐Ÿ”„ ุฑูุน..."
387
- create_backup "before_push"
 
 
 
 
 
 
388
 
389
- cleanup_temp
390
  mkdir -p "$TEMP_DIR"
391
 
392
  local repo_url="https://${G_TOKEN}@github.com/${G_NAME}.git"
393
 
 
394
  if ! GIT_TERMINAL_PROMPT=0 git clone --depth 1 --quiet "$repo_url" "$TEMP_DIR" 2>/dev/null; then
395
  cd "$TEMP_DIR"
396
  git init --quiet
397
  git remote add origin "$repo_url"
398
  echo "# Open WebUI Backup" > README.md
399
  git add README.md
400
- git config user.name "AutoSync"
401
  git config user.email "sync@local"
402
- git commit --quiet -m "Init" 2>/dev/null || true
403
- git push --quiet -u origin HEAD:main 2>/dev/null || true
404
  cd - > /dev/null
405
  fi
406
 
407
  cd "$TEMP_DIR"
408
- git config user.name "AutoSync"
409
  git config user.email "sync@local"
410
 
411
- sleep 2
412
  cp "$DB_FILE" ./webui.db
413
-
414
- if ! verify_sqlite "./webui.db"; then
415
- log_error "โŒ ุงู„ู†ุณุฎุฉ ุชุงู„ูุฉ"
416
- cd - > /dev/null
417
- cleanup_temp
418
- return 1
419
- fi
420
-
421
  git add webui.db
422
 
423
- if git diff --staged --quiet 2>/dev/null; then
424
- cd - > /dev/null
425
- cleanup_temp
426
- echo "$current_hash" > "$LOCAL_HASH_FILE"
427
- return 0
428
- fi
429
-
430
- git commit --quiet -m "Sync $(date '+%Y-%m-%d %H:%M') | โœ“verified" 2>/dev/null
431
- git pull --rebase --quiet origin main 2>/dev/null || true
432
-
433
- if git push --quiet origin HEAD:main 2>/dev/null || git push --quiet origin HEAD:master 2>/dev/null; then
434
- echo "$current_hash" > "$LOCAL_HASH_FILE"
435
- echo "$current_hash" > "$GITHUB_HASH_FILE"
436
- log_success "โฌ†๏ธ ุชู… ุงู„ุฑูุน!"
437
- cd - > /dev/null
438
- cleanup_temp
439
- return 0
440
  fi
441
 
442
  cd - > /dev/null
443
- cleanup_temp
444
- return 1
445
  }
446
 
447
  # ========================================
448
- # ุฏูˆุฑุฉ ุงู„ู…ุฒุงู…ู†ุฉ
449
  # ========================================
450
- sync_cycle() {
 
 
 
 
 
 
 
 
 
 
451
  log_info "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”"
452
- log_info "๐Ÿ”„ ุฏูˆุฑุฉ ุงู„ู…ุฒุงู…ู†ุฉ"
 
 
453
 
454
  if [[ -f "$DB_FILE" ]]; then
455
- log_info "๏ฟฝ๏ฟฝ๏ฟฝ DB: $(du -h "$DB_FILE" | cut -f1)"
456
  fi
457
 
458
- pull_from_github
459
- local pull_result=$?
460
 
461
- [[ $pull_result -ne 0 ]] && push_to_github
 
 
 
 
462
 
463
- log_success "ุงู†ุชู‡ุช ุงู„ุฏูˆุฑุฉ"
464
- log_info "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
465
  }
466
 
467
  # ========================================
468
- # Main
469
  # ========================================
470
- main() {
471
- log_info "=========================================="
472
- log_info " ๐Ÿ”„ Open WebUI Sync v7"
473
- log_info " ๐Ÿ”ง ู…ุน ุฅุตู„ุงุญ ุชู„ู‚ุงุฆูŠ + ุฏู…ุฌ"
474
- log_info "=========================================="
475
-
476
- check_requirements || exit 1
477
- verify_token || exit 1
478
-
479
- log_info "ุงู†ุชุธุงุฑ 60 ุซุงู†ูŠุฉ..."
480
- sleep 60
481
-
482
- sync_cycle
483
 
484
- local cycle=0
485
  while true; do
486
  cycle=$((cycle + 1))
487
- log_info "โฐ ุงู„ู‚ุงุฏู…ุฉ ููŠ ุณุงุนุฉ | ๐Ÿ’ค ุงู†ุชุธุงุฑ..."
 
 
 
 
 
 
 
 
 
 
488
  sleep $SYNC_INTERVAL
489
- log_info "๐Ÿ” ุฏูˆุฑุฉ #$((cycle+1))"
490
- sync_cycle
491
  done
492
- }
493
 
494
- main &
495
  SYNC_PID=$!
496
  echo $SYNC_PID > "$DATA_DIR/sync.pid" 2>/dev/null || true
497
- log_info "๐Ÿš€ PID: $SYNC_PID"
 
1
  #!/bin/bash
2
 
3
  # ========================================
4
+ # Open WebUI GitHub Sync v8
5
+ # ูŠู‚ุฑุฃ ุงู„ุจูŠุงู†ุงุช ุฃูˆู„ุงู‹ ุซู… ูŠูุญุฏู‘ุซ
6
  # ========================================
7
 
8
  set -eo pipefail
 
13
  readonly DB_FILE="/app/backend/data/webui.db"
14
  readonly DATA_DIR="./data"
15
  readonly TEMP_DIR="$DATA_DIR/git_temp"
16
+ readonly HASH_FILE="$DATA_DIR/last_hash.txt"
 
17
  readonly BACKUP_DIR="$DATA_DIR/backups"
18
  readonly MAX_BACKUPS=5
19
  readonly SYNC_INTERVAL=3600
 
30
  # ุงู„ุชุญู‚ู‚ ู…ู† ุงู„ู…ุชุทู„ุจุงุช
31
  # ========================================
32
  check_requirements() {
33
+ if [[ -z "${G_NAME:-}" ]] || [[ -z "${G_TOKEN:-}" ]]; then
34
+ log_error "G_NAME ุฃูˆ G_TOKEN ุบูŠุฑ ู…ูˆุฌูˆุฏ!"
 
 
 
 
 
 
 
35
  return 1
36
  fi
37
 
38
+ mkdir -p "$DATA_DIR" "$BACKUP_DIR" "$(dirname "$DB_FILE")"
39
  log_success "ุงู„ู…ุชุทู„ุจุงุช ู…ุชูˆูุฑุฉ | Repo: $G_NAME"
40
  return 0
41
  }
42
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  # ========================================
44
  # ุญุณุงุจ Hash
45
  # ========================================
46
+ get_hash() {
47
+ [[ -f "$1" ]] && sha256sum "$1" 2>/dev/null | cut -d' ' -f1 || echo "none"
48
  }
49
 
50
  # ========================================
51
+ # ุงู„ุชุญู‚ู‚ ู…ู† SQLite
52
  # ========================================
53
  verify_sqlite() {
54
+ [[ -f "$1" ]] && [[ -s "$1" ]] && sqlite3 "$1" "PRAGMA integrity_check;" 2>/dev/null | grep -q "ok"
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  }
56
 
57
  # ========================================
58
+ # ุฅุตู„ุงุญ SQLite
59
  # ========================================
60
+ repair_sqlite() {
61
+ local db="$1"
62
+ local tmp="${db}.tmp"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
 
64
+ log_warn "๐Ÿ”ง ุฅุตู„ุงุญ ู‚ุงุนุฏุฉ ุงู„ุจูŠุงู†ุงุช..."
 
 
 
65
 
66
+ # ู…ุญุงูˆู„ุฉ 1: recover
67
+ sqlite3 "$db" ".recover" 2>/dev/null | sqlite3 "$tmp" 2>/dev/null
68
+ if verify_sqlite "$tmp"; then
69
+ mv "$tmp" "$db" && log_success "ุชู… ุงู„ุฅุตู„ุงุญ" && return 0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
  fi
71
+ rm -f "$tmp"
72
 
73
+ # ู…ุญุงูˆู„ุฉ 2: dump
74
+ sqlite3 "$db" ".dump" 2>/dev/null | sqlite3 "$tmp" 2>/dev/null
75
+ if verify_sqlite "$tmp"; then
76
+ mv "$tmp" "$db" && log_success "ุชู… ุงู„ุฅุตู„ุงุญ" && return 0
 
 
 
 
 
77
  fi
78
+ rm -f "$tmp"
79
 
 
80
  return 1
81
  }
82
 
83
  # ========================================
84
+ # ุชู†ุธูŠู
85
  # ========================================
86
+ cleanup() {
87
+ rm -rf "$TEMP_DIR" 2>/dev/null || true
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  }
89
 
90
  # ========================================
91
  # ู†ุณุฎุฉ ุงุญุชูŠุงุทูŠุฉ
92
  # ========================================
93
+ backup() {
94
+ [[ -f "$DB_FILE" ]] || return
95
+ cp "$DB_FILE" "$BACKUP_DIR/${1:-backup}_$(date '+%Y%m%d_%H%M%S').db" 2>/dev/null
 
 
 
 
96
  ls -1t "$BACKUP_DIR"/*.db 2>/dev/null | tail -n +$((MAX_BACKUPS + 1)) | xargs rm -f 2>/dev/null || true
97
  }
98
 
99
  # ========================================
100
+ # โญ ุชุญู…ูŠู„ ู…ู† GitHub (ุงู„ุฏุงู„ุฉ ุงู„ุฑุฆูŠุณูŠุฉ)
 
 
 
 
 
 
 
101
  # ========================================
102
  pull_from_github() {
103
+ log_info "โฌ‡๏ธ ุชุญู…ูŠู„ ู…ู† GitHub..."
104
 
105
+ cleanup
106
  mkdir -p "$TEMP_DIR"
107
 
108
  local repo_url="https://${G_TOKEN}@github.com/${G_NAME}.git"
109
 
110
+ # Clone
111
  if ! GIT_TERMINAL_PROMPT=0 git clone --depth 1 --quiet "$repo_url" "$TEMP_DIR" 2>/dev/null; then
112
  log_info "ุงู„ู…ุณุชูˆุฏุน ูุงุฑุบ"
113
+ cleanup
114
  return 1
115
  fi
116
 
117
+ # ุงู„ุชุญู‚ู‚ ู…ู† ูˆุฌูˆุฏ ุงู„ู…ู„ู
118
+ if [[ ! -f "$TEMP_DIR/webui.db" ]] || [[ ! -s "$TEMP_DIR/webui.db" ]]; then
119
+ log_info "ู„ุง ูŠูˆุฌุฏ webui.db ููŠ GitHub"
120
+ cleanup
121
  return 1
122
  fi
123
 
124
  local github_db="$TEMP_DIR/webui.db"
125
+ local github_size=$(du -h "$github_db" | cut -f1)
126
+ log_info "ุญุฌู… ู…ู„ู GitHub: $github_size"
 
 
 
 
 
 
 
 
 
 
127
 
128
+ # ูุญุต ูˆุฅุตู„ุงุญ ุฅุฐุง ู„ุฒู…
129
+ if ! verify_sqlite "$github_db"; then
130
+ log_warn "ู…ู„ู GitHub ุชุงู„ู - ู…ุญุงูˆู„ุฉ ุงู„ุฅุตู„ุงุญ..."
131
+ repair_sqlite "$github_db" || { cleanup; return 1; }
132
  fi
133
 
134
+ # ู†ุณุฎุฉ ุงุญุชูŠุงุทูŠุฉ ู…ู† ุงู„ู…ุญู„ูŠ
135
+ [[ -f "$DB_FILE" ]] && backup "before_pull"
 
136
 
137
+ # โญ ู†ุณุฎ ุงู„ู…ู„ู
138
+ cp "$github_db" "$DB_FILE"
139
+ chmod 666 "$DB_FILE"
140
 
141
+ # ุญูุธ ุงู„ู€ hash
142
+ get_hash "$DB_FILE" > "$HASH_FILE"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
 
144
+ log_success "โœ… ุชู… ุชุญู…ูŠู„ ุงู„ุจูŠุงู†ุงุช ู…ู† GitHub ($github_size)"
145
+ cleanup
146
+ return 0
 
147
  }
148
 
149
  # ========================================
150
+ # โญ ุฑูุน ุฅู„ู‰ GitHub
151
  # ========================================
152
  push_to_github() {
153
+ log_info "โฌ†๏ธ ุฑูุน ุฅู„ู‰ GitHub..."
154
 
155
+ # ุงู„ุชุญู‚ู‚ ู…ู† ูˆุฌูˆุฏ ุงู„ู…ู„ู
156
  if [[ ! -f "$DB_FILE" ]]; then
157
+ log_warn "ู„ุง ูŠูˆุฌุฏ ู…ู„ู ู„ู„ุฑูุน"
158
  return 1
159
  fi
160
 
161
+ # ุงู„ุชุญู‚ู‚ ู…ู† ุงู„ุชุบูŠูŠุฑุงุช
162
+ local current_hash=$(get_hash "$DB_FILE")
163
+ local saved_hash=$(cat "$HASH_FILE" 2>/dev/null || echo "none")
 
 
 
 
 
 
164
 
165
+ if [[ "$current_hash" == "$saved_hash" ]]; then
166
+ log_info "โœ“ ู„ุง ุชูˆุฌุฏ ุชุบูŠูŠุฑุงุช"
 
 
 
167
  return 0
168
  fi
169
 
170
+ # ูุญุต ุงู„ู…ู„ู
171
+ if ! verify_sqlite "$DB_FILE"; then
172
+ log_warn "ุงู„ู…ู„ู ุงู„ู…ุญู„ูŠ ุชุงู„ู - ู…ุญุงูˆู„ุฉ ุงู„ุฅุตู„ุงุญ..."
173
+ backup "corrupted"
174
+ repair_sqlite "$DB_FILE" || return 1
175
+ fi
176
+
177
+ backup "before_push"
178
 
179
+ cleanup
180
  mkdir -p "$TEMP_DIR"
181
 
182
  local repo_url="https://${G_TOKEN}@github.com/${G_NAME}.git"
183
 
184
+ # Clone ุฃูˆ Init
185
  if ! GIT_TERMINAL_PROMPT=0 git clone --depth 1 --quiet "$repo_url" "$TEMP_DIR" 2>/dev/null; then
186
  cd "$TEMP_DIR"
187
  git init --quiet
188
  git remote add origin "$repo_url"
189
  echo "# Open WebUI Backup" > README.md
190
  git add README.md
191
+ git config user.name "Sync"
192
  git config user.email "sync@local"
193
+ git commit -m "init" --quiet 2>/dev/null || true
 
194
  cd - > /dev/null
195
  fi
196
 
197
  cd "$TEMP_DIR"
198
+ git config user.name "Sync"
199
  git config user.email "sync@local"
200
 
201
+ # ู†ุณุฎ ุงู„ู…ู„ู
202
  cp "$DB_FILE" ./webui.db
 
 
 
 
 
 
 
 
203
  git add webui.db
204
 
205
+ # Commit & Push
206
+ if ! git diff --staged --quiet 2>/dev/null; then
207
+ git commit -m "Sync $(date '+%Y-%m-%d %H:%M')" --quiet
208
+
209
+ if git push origin HEAD:main --quiet 2>/dev/null || \
210
+ git push -u origin HEAD:main --quiet 2>/dev/null || \
211
+ git push origin HEAD:master --quiet 2>/dev/null; then
212
+ echo "$current_hash" > "$HASH_FILE"
213
+ log_success "โœ… ุชู… ุงู„ุฑูุน ุจู†ุฌุงุญ"
214
+ else
215
+ log_error "ูุดู„ ุงู„ุฑูุน"
216
+ cd - > /dev/null
217
+ cleanup
218
+ return 1
219
+ fi
 
 
220
  fi
221
 
222
  cd - > /dev/null
223
+ cleanup
224
+ return 0
225
  }
226
 
227
  # ========================================
228
+ # โญ ุงู„ุฏุงู„ุฉ ุงู„ุฑุฆูŠุณูŠุฉ
229
  # ========================================
230
+ main() {
231
+ log_info "=========================================="
232
+ log_info " ๐Ÿ”„ Open WebUI GitHub Sync v8"
233
+ log_info "=========================================="
234
+
235
+ # ุงู„ุชุญู‚ู‚ ู…ู† ุงู„ู…ุชุทู„ุจุงุช
236
+ check_requirements || exit 1
237
+
238
+ # โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”
239
+ # โญ ุงู„ุฎุทูˆุฉ 1: ุชุญู…ูŠู„ ุงู„ุจูŠุงู†ุงุช ููˆุฑุงู‹ (ู‚ุจู„ ุฃูŠ ุดูŠุก)
240
+ # โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”
241
  log_info "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”"
242
+ log_info "๐Ÿ“ฅ ุงู„ู…ุฒุงู…ู†ุฉ ุงู„ุฃูˆู„ูŠุฉ..."
243
+
244
+ pull_from_github
245
 
246
  if [[ -f "$DB_FILE" ]]; then
247
+ log_info "๐Ÿ“Š ุญุฌู… DB: $(du -h "$DB_FILE" | cut -f1)"
248
  fi
249
 
250
+ log_info "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”"
 
251
 
252
+ # โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”
253
+ # โญ ุงู„ุฎุทูˆุฉ 2: ุงู†ุชุธุงุฑ ุจุฏุก ุงู„ุชุทุจูŠู‚ ุซู… ุงู„ู…ุฒุงู…ู†ุฉ ุงู„ุฏูˆุฑูŠุฉ
254
+ # โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”
255
+ log_info "โณ ุงู†ุชุธุงุฑ 2 ุฏู‚ูŠู‚ุฉ ู„ุจุฏุก Open WebUI..."
256
+ sleep 120
257
 
258
+ local cycle=0
259
+ while true; do
260
+ cycle=$((cycle + 1))
261
+
262
+ log_info "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”"
263
+ log_info "๐Ÿ”„ ุฏูˆุฑุฉ ุงู„ู…ุฒุงู…ู†ุฉ #$cycle"
264
+
265
+ if [[ -f "$DB_FILE" ]]; then
266
+ log_info "๐Ÿ“Š ุญุฌู… DB: $(du -h "$DB_FILE" | cut -f1)"
267
+ fi
268
+
269
+ # ุฑูุน ุงู„ุชุบูŠูŠุฑุงุช
270
+ push_to_github
271
+
272
+ log_info "โฐ ุงู„ู…ุฒุงู…ู†ุฉ ุงู„ู‚ุงุฏู…ุฉ ุจุนุฏ ุณุงุนุฉ"
273
+ log_info "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”"
274
+
275
+ sleep $SYNC_INTERVAL
276
+ done
277
  }
278
 
279
  # ========================================
280
+ # ุงู„ุชุดุบูŠู„
281
  # ========================================
282
+
283
+ # โญ ู…ู‡ู…: ุชุดุบูŠู„ ุงู„ุชุญู…ูŠู„ ุงู„ุฃูˆู„ูŠ ููŠ ุงู„ู…ู‚ุฏู…ุฉ (ู„ูŠุณ ููŠ ุงู„ุฎู„ููŠุฉ)
284
+ # ู‡ุฐุง ูŠุถู…ู† ุชุญู…ูŠู„ ุงู„ุจูŠุงู†ุงุช ู‚ุจู„ ุจุฏุก Open WebUI
285
+
286
+ log_info "๐Ÿš€ ุจุฏุก ุณูƒุฑุจุช ุงู„ู…ุฒุงู…ู†ุฉ..."
287
+
288
+ # ุชุญู…ูŠู„ ุงู„ุจูŠุงู†ุงุช ุฃูˆู„ุงู‹ (ุจุดูƒู„ ู…ุชุฒุงู…ู†)
289
+ check_requirements && pull_from_github
290
+
291
+ # ุซู… ุจุฏุก ุงู„ู…ุฒุงู…ู†ุฉ ุงู„ุฏูˆุฑูŠุฉ ููŠ ุงู„ุฎู„ููŠุฉ
292
+ (
293
+ sleep 120
 
294
 
295
+ cycle=0
296
  while true; do
297
  cycle=$((cycle + 1))
298
+
299
+ log_info "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”"
300
+ log_info "๐Ÿ”„ ุฏูˆุฑุฉ #$cycle"
301
+
302
+ [[ -f "$DB_FILE" ]] && log_info "๐Ÿ“Š DB: $(du -h "$DB_FILE" | cut -f1)"
303
+
304
+ push_to_github || true
305
+
306
+ log_info "โฐ ุงู„ู‚ุงุฏู…ุฉ ุจุนุฏ ุณุงุนุฉ"
307
+ log_info "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”"
308
+
309
  sleep $SYNC_INTERVAL
 
 
310
  done
311
+ ) &
312
 
 
313
  SYNC_PID=$!
314
  echo $SYNC_PID > "$DATA_DIR/sync.pid" 2>/dev/null || true
315
+ log_info "โœ… ุงู„ู…ุฒุงู…ู†ุฉ ุงู„ุฏูˆุฑูŠุฉ ุชุนู…ู„ (PID: $SYNC_PID)"