| Server IP : 202.61.199.114 / Your IP : 216.73.217.139 Web Server : nginx/1.22.1 System : Linux de.arni-solutions.de 6.1.0-49-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.174-1 (2026-05-26) x86_64 User : web20 ( 1018) PHP Version : 8.4.23 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /usr/local/bin/ |
Upload File : |
#!/usr/bin/env bash
# =============================================================================
# Visit-X Cam Status-Sync — taschenmuschi-kaufen.de
#
# Modi:
# (default) STATUS-REFRESH:
# Holt ALLE aktuell-online Cam-IDs von der Visit-X API (paginiert)
# und setzt _vx_online + _vx_last_online ENTSPRECHEND in der DB.
# KEIN Beschreibungstext-Update, KEINE neuen Cams importieren.
# Schnell — fuer alle 15 Min via Cron geeignet.
#
# --full VOLL-SYNC:
# Ruft VXLC_Plugin::instance()->syncer->run() auf.
# Importiert neue Cams + updated alles (inkl. Text).
# Laenger — sollte seltener laufen (z.B. 1x taeglich).
#
# Locking: flock auf /var/lock/tmk-vxlc-sync.lock (Single-Instance)
# Logging: /var/log/tmk-vxlc-sync.log
# =============================================================================
set -euo pipefail
SITE=/var/www/taschenmuschi-kaufen.de/web
PHP=/usr/bin/php8.4
LOCK=/var/lock/tmk-vxlc-sync.lock
LOG=/var/log/tmk-vxlc-sync.log
MODE=status
for arg in "$@"; do
case "$arg" in
--full) MODE=full ;;
--status) MODE=status ;;
*) echo "Unknown flag: $arg" >&2; exit 2 ;;
esac
done
ts() { date +"%Y-%m-%d %H:%M:%S"; }
# Logfile-Setup (idempotent)
if [ ! -f "$LOG" ]; then
touch "$LOG" 2>/dev/null || true
chown web32:client2 "$LOG" 2>/dev/null || true
chmod 664 "$LOG" 2>/dev/null || true
fi
# Lock fuer Single-Instance
exec 9>"$LOCK" 2>/dev/null || {
echo "[$(ts)] [$MODE] FEHLER: Lock-File $LOCK nicht zu oeffnen" >>"$LOG"
exit 2
}
if ! flock -n 9; then
echo "[$(ts)] [$MODE] Anderer Sync laeuft — Skip" >>"$LOG"
exit 0
fi
[ -f "$SITE/wp-load.php" ] || { echo "[$(ts)] FEHLER: wp-load.php fehlt" >>"$LOG"; exit 2; }
[ -x "$PHP" ] || { echo "[$(ts)] FEHLER: $PHP fehlt" >>"$LOG"; exit 2; }
START=$(date +%s)
echo "[$(ts)] === Sync START ($MODE) ===" >>"$LOG"
case "$MODE" in
status)
# -----------------------------------------------------------------------
# STATUS-REFRESH — paginiert die ONLINE-Cams von der Visit-X API,
# vergleicht mit der DB und korrigiert nur _vx_online + _vx_last_online.
# Beschreibungstext wird NICHT angefasst.
# -----------------------------------------------------------------------
SYNC_OUT=$(timeout 300 "$PHP" \
-d memory_limit=256M \
-d max_execution_time=300 \
-r "
define('WP_USE_THEMES', false);
define('DOING_CRON', true);
require '$SITE/wp-load.php';
if ( ! class_exists('VXLC_Plugin') ) {
fwrite(STDERR, 'VXLC_Plugin nicht geladen — Plugin nicht aktiv?');
exit(1);
}
\$client = VXLC_Plugin::instance()->client;
global \$wpdb;
\$started = microtime(true);
// ---- Phase A: ALLE online-Cam-IDs holen ----
\$online_ids = [];
\$offset = 0;
\$page_size = 100;
\$max_pages = 80; // Safety-Limit (= 8000 Cams)
for (\$i = 0; \$i < \$max_pages; \$i++) {
\$page = \$client->fetch_models([
'online' => true,
'offset' => \$offset,
'first' => \$page_size,
]);
if ( empty(\$page) ) break;
foreach (\$page as \$m) {
\$online_ids[ (int) \$m['id'] ] = true;
}
if ( count(\$page) < \$page_size ) break;
\$offset += \$page_size;
}
if ( empty(\$online_ids) ) {
fwrite(STDERR, 'WARN: API lieferte 0 online-Cams — Sync abgebrochen, kein Update');
exit(0);
}
// ---- Phase B: DB-Zustand BEFORE ----
\$before_online = (int) \$wpdb->get_var(\"SELECT COUNT(*) FROM {\$wpdb->postmeta} WHERE meta_key='_vx_online' AND meta_value='1'\");
\$before_offline = (int) \$wpdb->get_var(\"SELECT COUNT(*) FROM {\$wpdb->postmeta} WHERE meta_key='_vx_online' AND meta_value='0'\");
// ---- Phase C: Updates ----
\$ids_csv = implode(',', array_map('intval', array_keys(\$online_ids)));
\$now = time();
// C1: _vx_online=1 fuer alle Cams deren _vx_cam_id in der online-Liste ist
\$set_online = \$wpdb->query(\"
UPDATE {\$wpdb->postmeta} pm
JOIN {\$wpdb->postmeta} pm2 ON pm2.post_id = pm.post_id AND pm2.meta_key='_vx_cam_id'
SET pm.meta_value = '1'
WHERE pm.meta_key='_vx_online'
AND pm.meta_value != '1'
AND CAST(pm2.meta_value AS UNSIGNED) IN (\$ids_csv)
\");
// C2: _vx_last_online auf jetzt fuer online-Cams (insert oder update)
// Hier nur Update; Insert nur falls Meta fehlt
\$wpdb->query(\"
UPDATE {\$wpdb->postmeta} pm
JOIN {\$wpdb->postmeta} pm2 ON pm2.post_id = pm.post_id AND pm2.meta_key='_vx_cam_id'
SET pm.meta_value = '{\$now}'
WHERE pm.meta_key='_vx_last_online'
AND CAST(pm2.meta_value AS UNSIGNED) IN (\$ids_csv)
\");
// Insert fuer Cams ohne _vx_last_online (Erstkontakt)
\$wpdb->query(\"
INSERT INTO {\$wpdb->postmeta} (post_id, meta_key, meta_value)
SELECT pm2.post_id, '_vx_last_online', '{\$now}'
FROM {\$wpdb->postmeta} pm2
LEFT JOIN {\$wpdb->postmeta} pm_lo ON pm_lo.post_id = pm2.post_id AND pm_lo.meta_key='_vx_last_online'
WHERE pm2.meta_key='_vx_cam_id'
AND CAST(pm2.meta_value AS UNSIGNED) IN (\$ids_csv)
AND pm_lo.meta_id IS NULL
\");
// C3: _vx_online=0 fuer alle Cams die NICHT in der online-Liste sind UND aktuell auf 1
\$set_offline = \$wpdb->query(\"
UPDATE {\$wpdb->postmeta} pm
JOIN {\$wpdb->postmeta} pm2 ON pm2.post_id = pm.post_id AND pm2.meta_key='_vx_cam_id'
SET pm.meta_value = '0'
WHERE pm.meta_key='_vx_online'
AND pm.meta_value = '1'
AND CAST(pm2.meta_value AS UNSIGNED) NOT IN (\$ids_csv)
\");
// ---- Phase D: AFTER ----
\$after_online = (int) \$wpdb->get_var(\"SELECT COUNT(*) FROM {\$wpdb->postmeta} WHERE meta_key='_vx_online' AND meta_value='1'\");
\$after_offline = (int) \$wpdb->get_var(\"SELECT COUNT(*) FROM {\$wpdb->postmeta} WHERE meta_key='_vx_online' AND meta_value='0'\");
\$dur = (int) ((microtime(true) - \$started) * 1000);
\$api = count(\$online_ids);
update_option('vxlc_last_status_sync', [
'api_online' => \$api,
'set_online' => (int) \$set_online,
'set_offline' => (int) \$set_offline,
'before_online' => \$before_online,
'after_online' => \$after_online,
'duration_ms' => \$dur,
'at' => current_time('mysql'),
], false);
echo \"api_online=\$api set_online=\$set_online set_offline=\$set_offline total_online_before=\$before_online after=\$after_online duration=\${dur}ms\";
" 2>&1) || EXIT_CODE=$?
;;
full)
# -----------------------------------------------------------------------
# VOLL-SYNC — Plugin-Syncer komplett
# -----------------------------------------------------------------------
SYNC_OUT=$(timeout 1800 "$PHP" \
-d memory_limit=512M \
-d max_execution_time=1800 \
-r "
define('WP_USE_THEMES', false);
define('DOING_CRON', true);
require '$SITE/wp-load.php';
if ( ! class_exists('VXLC_Plugin') ) {
fwrite(STDERR, 'VXLC_Plugin nicht geladen');
exit(1);
}
try {
\$plugin = VXLC_Plugin::instance();
\$plugin->syncer->run();
\$last = get_option('vxlc_last_sync', []);
if ( is_array(\$last) ) {
\$tot = \$last['total'] ?? 'n/a';
\$imp = \$last['imported'] ?? 'n/a';
\$upd = \$last['updated'] ?? 'n/a';
\$err = \$last['errors'] ?? 'n/a';
\$dur = \$last['duration_ms'] ?? 'n/a';
echo \"total=\$tot imported=\$imp updated=\$upd errors=\$err duration=\${dur}ms\";
} else {
echo 'OK';
}
} catch (Throwable \$e) {
fwrite(STDERR, 'Sync FAIL: ' . \$e->getMessage() . ' @ ' . \$e->getFile() . ':' . \$e->getLine());
exit(1);
}
" 2>&1) || EXIT_CODE=$?
;;
esac
EXIT_CODE=${EXIT_CODE:-0}
ELAPSED=$(( $(date +%s) - START ))
if [ "$EXIT_CODE" -eq 0 ]; then
echo "[$(ts)] [$MODE] $SYNC_OUT" >>"$LOG"
echo "[$(ts)] === Sync OK ($MODE, ${ELAPSED}s) ===" >>"$LOG"
elif [ "$EXIT_CODE" -eq 124 ]; then
echo "[$(ts)] [$MODE] TIMEOUT" >>"$LOG"
else
echo "[$(ts)] [$MODE] EXIT=$EXIT_CODE" >>"$LOG"
echo "$SYNC_OUT" >>"$LOG"
echo "[$(ts)] === Sync FAILED ($MODE, ${ELAPSED}s) ===" >>"$LOG"
fi
exit $EXIT_CODE