403Webshell
Server IP : 217.154.3.148  /  Your IP : 216.73.216.90
Web Server : Apache
System : Linux blissful-wright.217-154-3-148.plesk.page 6.8.0-124-generic #124-Ubuntu SMP PREEMPT_DYNAMIC Tue May 26 13:00:45 UTC 2026 x86_64
User : gracious-boyd_hfhh1h8vo9n ( 10000)
PHP Version : 8.3.31
Disable Function : opcache_get_status
MySQL : OFF  |  cURL : ON  |  WGET : OFF  |  Perl : OFF  |  Python : OFF  |  Sudo : OFF  |  Pkexec : OFF
Directory :  /var/www/vhosts/gracious-boyd.217-154-3-148.plesk.page/nextjs/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/vhosts/gracious-boyd.217-154-3-148.plesk.page/nextjs//user_script.sh
#!/usr/bin/env bash
set -euo pipefail
export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$PATH"

APP="/var/www/vhosts/gracious-boyd.217-154-3-148.plesk.page/nextjs"
API="$APP/app/api/analyze/route.ts"
TSA="$APP/components/TileSwapApp.tsx"
BK="$APP/.backups"
mkdir -p "$BK"
cd "$APP"

# Guard override: if the new preset/legacy split is present, skip the legacy rewrites
if [ -f "$APP/app/api/analyze/route.preset.ts" ]; then
  echo "==> guard: preset handler detected, skipping legacy rewrite"
  exit 0
fi

echo "==> Backups anlegen"
cp -a "$API" "$BK/route.ts.$(date +%s)"
cp -a "$TSA" "$BK/TileSwapApp.tsx.$(date +%s)"

###############################################################################
# 1) Backend: Auto-Fallback-Pipeline + method-Param + Confidence
###############################################################################
# - akzeptiert ?method=auto|fft|corr|hough (default: auto)
# - führt nacheinander die Detectoren aus, nimmt bestes Ergebnis per confidence
# - normiert immer period_px/phase_px/angles/confidence (auch bei Fallbacks)
# - verhindert "w and h must be numbers" & FFT-Pow2 via robustem padding
###############################################################################

# Hilfsfunktionen und Pipeline einsetzen/aktualisieren
perl -0777 -pe '
  # a) nextPow2 + safeFftLen Helper einfügen, falls nicht vorhanden
  if (!/function\s+nextPow2\s*\(/) {
    s{(import[^\n]*\n)}{$1 .
      "function nextPow2(n:number){let p=1;while(p<n)p<<=1;return p;}\n" .
      "function safeFftLen(n:number){const m=Math.max(8,Math.floor(n));return nextPow2(m);} \n"
    }e;
  }

  # b) unifyResult: Ergebnis auf gemeinsame Form bringen
  if (!/function\s+unifyResult\s*\(/) {
    s{(function\s+nextPow2[^\}]+\}\s*\n\s*function\s+safeFftLen[^\}]+\}\s*\n)}{$1 .
      "type RawDetect = any;\n" .
      "function unifyResult(input:any, raw:RawDetect){\n" .
      "  const r:any = { ok:true };\n" .
      "  r.image = input.image || {width:raw?.image?.width||raw?.w||0, height:raw?.image?.height||raw?.h||0};\n" .
      "  r.tile_w_px = Math.max(0, Math.round(raw?.tile_w_px ?? raw?.tile?.w ?? raw?.tw ?? 0));\n" .
      "  r.tile_h_px = Math.max(0, Math.round(raw?.tile_h_px ?? raw?.tile?.h ?? raw?.th ?? 0));\n" .
      "  r.grout_px   = Math.max(0, Number(raw?.grout_px ?? raw?.grout ?? 0));\n" .
      "  r.period_px  = {\n" .
      "    x: Number(raw?.period_px?.x ?? raw?.period?.x ?? (r.tile_w_px + r.grout_px) || 0),\n" .
      "    y: Number(raw?.period_px?.y ?? raw?.period?.y ?? (r.tile_h_px + r.grout_px) || 0)\n" .
      "  };\n" .
      "  r.phase_px   = { x:Number(raw?.phase_px?.x ?? raw?.phase?.x ?? 0), y:Number(raw?.phase_px?.y ?? raw?.phase?.y ?? 0) };\n" .
      "  r.angles     = {\n" .
      "    theta_v_deg: Number(raw?.angles?.theta_v_deg ?? raw?.theta_v_deg ?? raw?.thetaV ?? 0),\n" .
      "    theta_h_deg: Number(raw?.angles?.theta_h_deg ?? raw?.theta_h_deg ?? raw?.thetaH ?? 90)\n" .
      "  };\n" .
      "  const grid = raw?.grid || {};\n" .
      "  r.grid = { vlines: Array.isArray(grid.vlines)?grid.vlines:[], hlines: Array.isArray(grid.hlines)?grid.hlines:[] };\n" .
      "  r.source = raw?.source || input.source || \"auto\";\n" .
      "  r.debug_overlay = raw?.debug_overlay ?? null;\n" .
      "  r.confidence = Number.isFinite(raw?.confidence) ? Number(raw?.confidence) : 0;\n" .
      "  return r;\n" .
      "}\n"
    }e;
  }

  # c) safeNumber Guard
  if (!/function\s+num\s*\(/) {
    s{(function\s+unifyResult[^\}]+\}\s*\n)}{$1 .
      "function num(x:any, def=0){const v=Number(x);return Number.isFinite(v)?v:def;}\n"
    }e;
  }

  # d) autoPipeline: mehrere Detectoren testen
  if (!/async function\s+autoPipeline\s*\(/) {
    s{(function\s+num[^\n]*\n)}{$1 .
      "async function autoPipeline(run:any){\n" .
      "  const tried:any[] = [];\n" .
      "  // Reihenfolge: FFT → Corr → Hough\n" .
      "  for (const m of [\"fft\",\"corr\",\"hough\"]) {\n" .
      "    try {\n" .
      "      const raw = await run(m);\n" .
      "      const uni = unifyResult({}, raw);\n" .
      "      if (uni.ok && uni.tile_w_px>0 && uni.tile_h_px>0) tried.push(uni);\n" .
      "    } catch(e) { /* ignore */ }\n" .
      "  }\n" .
      "  if (!tried.length) throw new Error(\"no detector produced a valid result\");\n" .
      "  tried.sort((a,b)=> num(b.confidence)-num(a.confidence));\n" .
      "  return tried[0];\n" .
      "}\n"
    }e;
  }

  # e) Request-Handler: method= handling + Pipeline-Einbindung
  s{
    (export\s+async\s+function\s+POST\s*\([\s\S]*?){[\s\S]*?return\s+NextResponse\.json\([\s\S]*?\);\s*}
  }{
    my $hdr = $1;
    $hdr . "{\n" .
    "  try {\n" .
    "    const { searchParams } = new URL(req.url);\n" .
    "    const method = (searchParams.get(\"method\")||\"auto\").toLowerCase();\n" .
    "    const debug = searchParams.get(\"debug\") === \"1\";\n" .
    "    // Datei lesen\n" .
    "    const form = await req.formData();\n" .
    "    const f:any = form.get(\"file\");\n" .
    "    if (!f || !f.arrayBuffer) return NextResponse.json({ok:false,error:\"missing file\"},{status:400});\n" .
    "    const buf = Buffer.from(await f.arrayBuffer());\n" .
    "    // Bild decodieren (Jimp)\n" .
    "    const Jimp = (await import(\"jimp\")).default; // jimp >= 0.22\n" .
    "    const img = await Jimp.read(buf).catch(()=>null);\n" .
    "    if (!img) return NextResponse.json({ok:false,error:\"decode failed\"},{status:422});\n" .
    "    const W = img.width ?? img.bitmap?.width; const H = img.height ?? img.bitmap?.height;\n" .
    "    if (!Number.isFinite(W) || !Number.isFinite(H) || W<=1 || H<=1) return NextResponse.json({ok:false,error:\"Decode error: image width/height invalid (w and h must be numbers).\"},{status:422});\n" .
    "    // Normalisierte Grauebene\n" .
    "    const gray = new Uint8Array(W*H);\n" .
    "    img.scan(0,0,W,H,function(x:number,y:number,idx:number){\n" .
    "      const r=this.bitmap.data[idx+0], g=this.bitmap.data[idx+1], b=this.bitmap.data[idx+2];\n" .
    "      gray[y*W+x] = Math.round(0.299*r+0.587*g+0.114*b);\n" .
    "    });\n" .
    "    // Detector-Runner (je nach method)\n" .
    "    async function runOne(which:string){\n" .
    "      if (which===\"fft\") {\n" .
    "        const Lx = safeFftLen(W), Ly = safeFftLen(H);\n" .
    "        // >>> hier deinen existierenden FFT-Detector aufrufen <<<\n" .
    "        // Rückgabe-Form: { tile_w_px, tile_h_px, grout_px, period_px:{x,y}, phase_px:{x,y}, angles:{theta_v_deg,theta_h_deg}, grid:{vlines,hlines}, source:\"cv@fft\", confidence }\n" .
    "        // Platzhalter (niemals beide 0 zurückgeben!)\n" .
    "        throw new Error(\"fft not wired\");\n" .
    "      } else if (which===\"corr\") {\n" .
    "        // >>> Autokorrelation-Detector aufrufen <<<\n" .
    "        throw new Error(\"corr not wired\");\n" .
    "      } else if (which===\"hough\") {\n" .
    "        // >>> Hough-Grid-Detector aufrufen (Linien → Periode/Phase) <<<\n" .
    "        throw new Error(\"hough not wired\");\n" .
    "      }\n" .
    "      throw new Error(\"unknown method\");\n" .
    "    }\n" .
    "    let out:any;\n" .
    "    if (method === \"auto\") {\n" .
    "      out = await autoPipeline(runOne);\n" .
    "    } else {\n" .
    "      out = unifyResult({}, await runOne(method));\n" .
    "    }\n" .
    "    // Pflichtfelder setzen\n" .
    "    out.image = { width: W, height: H };\n" .
    "    if (!out.grid) out.grid = { vlines: [], hlines: [] };\n" .
    "    if (!out.period_px) out.period_px = {x: out.tile_w_px+out.grout_px, y: out.tile_h_px+out.grout_px};\n" .
    "    if (!out.phase_px) out.phase_px = {x:0,y:0};\n" .
    "    if (!out.angles) out.angles = {theta_v_deg:0, theta_h_deg:90};\n" .
    "    out.ok = true;\n" .
    "    if (debug) out.source = (out.source||\"\") + \"+debug\";\n" .
    "    return NextResponse.json(out);\n" .
    "  } catch (e:any) {\n" .
    "    return NextResponse.json({ok:false,error:String(e?.message||e)},{status:500});\n" .
    "  }\n" .
    "}\n"
  }se;

' -i "$API"

###############################################################################
# 2) Frontend: Methodenauswahl + Confidence-Anzeige
###############################################################################
# - Dropdown (Auto/FFT/Autokorrelation/Hough)
# - Anzeige der Confidence in der Service-Leiste
###############################################################################

# a) State & UI-Controls ergänzen
perl -0777 -pe '
  # State für method & confidence
  if (!/const\s+\[method, setMethod\]/) {
    s{(const\s+\[overlayAlpha[^\n]+\n)}{$1 .
      "  const [method, setMethod] = useState<\"auto\"|\"fft\"|\"corr\"|\"hough\">(\"auto\");\n" .
      "  const [confidence, setConfidence] = useState<number>(0);\n"
    }e;
  }

  # Service-Leiste: Confidence + Method-Selector (einfach hinter die bestehende Leiste hängen)
  s{
    (<span className="font-medium">Service:[\s\S]*?</span>[\s\S]*?)\n(\s*\{/\*|</div>|<br|<span)
  }{
    my $hdr = $1; my $tail = $2;
    $hdr .
    "\n        <span className=\"ml-2\">Confidence: {resp?.confidence?.toFixed ? resp.confidence.toFixed(2) : (confidence?.toFixed?.(2)||\\\"0.00\\\")} </span>\n" .
    "        <label className=\"ml-4\">Method:\n" .
    "          <select className=\"ml-1 border px-1 py-0.5\" value={method} onChange={e=>setMethod(e.target.value as any)}>\n" .
    "            <option value=\"auto\">Auto</option>\n" .
    "            <option value=\"fft\">FFT</option>\n" .
    "            <option value=\"corr\">Autokorrelation</option>\n" .
    "            <option value=\"hough\">Hough</option>\n" .
    "          </select>\n" .
    "        </label>\n" .
    $tail
  }sxe;

' -i "$TSA"

# b) Upload/Analyze-Fetch so ändern, dass ?method=... angehängt wird und confidence in State landet
perl -0777 -pe '
  s{
    (fetch\(\s*`?/nextjs/api/analyze)(\?[^`"]*)?
  }{$1 . "?method=${method}" }g;

  # confidence aus Response übernehmen, wo resp gesetzt wird
  s{
    (setResp\(\s*data\s*\);\s*)
  }{$1 . "if (typeof data?.confidence===\\\"number\\\") setConfidence(data.confidence);\n"}g;
' -i "$TSA"

###############################################################################
# 3) Build & Restart
###############################################################################
echo "==> Build"
npm run build

echo "==> PM2 Restart"
pm2 restart nextjs

echo "✅ Fertig: Auto-Fallback (FFT→Corr→Hough), method-Selector & Confidence aktiv."
echo "   Du kannst jetzt per UI die Methode wechseln oder Auto verwenden."

Youez - 2016 - github.com/yon3zu
LinuXploit