Full blog engine source: build_blog.py, content, deploy scripts

This commit is contained in:
2026-06-28 17:36:44 +00:00
commit 7767979538
34 changed files with 3272 additions and 0 deletions

52
README.md Normal file
View File

@ -0,0 +1,52 @@
# GFIL BLOG — Trading Insights & Free Tools
The content engine behind [blog.quant-view.xyz](https://blog.quant-view.xyz) — a multi-language trading education site with 80+ free calculators, professional market analysis, and SEO-optimized articles.
## What's here
- **17 in-depth articles** (EN/ZH/ES/AR) on forex, gold, risk management, and trading technology
- **80+ free trading calculators** — position size, pip value, Fibonacci, ATR, Kelly, pivot points, and more
- **Full SEO/GEO stack** — Schema JSON-LD, hreflang, sitemap (339 URLs), robots.txt, llms.txt
- **Automated deployment pipeline** — build, upload, and server-side promotion scripts
## How it works
```
blog_content/ → build_blog.py → output/ → RackNerd /var/www/blog/
tools/ → → (static HTML served by Nginx)
deploy_scripts/ → daily cron jobs on server
```
## Quick start
```bash
# Build locally (no deploy)
python build_blog.py --no-upload
# Build and deploy (requires .env with SSH credentials)
python build_blog.py
# Preview locally
python build_blog.py --no-upload --serve
```
## Repository structure
| Directory | Purpose |
|-----------|---------|
| `blog_content/` | Article HTML source (17 articles × 4 languages) |
| `tools/` | 145 calculator pages + GEO entity pages + images |
| `deploy_scripts/` | Automation: daily promotion, SEO monitoring, IndexNow |
| `chrome_extension/` | Chrome extension source |
| `colab_notebooks/` | Google Colab trading notebooks |
| `config.py` | Configuration loader (reads from `.env`) |
## Languages
English · 中文 · Español · العربية
## Links
- Blog: [blog.quant-view.xyz](https://blog.quant-view.xyz)
- Terminal: [gfil-intel.xyz](https://gfil-intel.xyz)
- Community: [t.me/GFIL_Trading](https://t.me/GFIL_Trading) · [Discord](https://discord.gg/GMmMCD4MCr)

70
add_robots_location.py Normal file
View File

@ -0,0 +1,70 @@
"""Safely add robots.txt location block to gfil-lab.com Nginx config"""
import paramiko
JD_HOST = "111.228.37.165"
JD_USER = "root"
JD_PASS = "Liudecai110"
LAB_HOST = "216.144.233.14"
LAB_USER = "root"
LAB_PASS = "Kt9V72Tx2c48ChikKU"
jd = paramiko.SSHClient()
jd.set_missing_host_key_policy(paramiko.AutoAddPolicy())
jd.connect(JD_HOST, port=22, username=JD_USER, password=JD_PASS,
timeout=20, banner_timeout=60, allow_agent=False, look_for_keys=False)
# Use python on remote to do precise insertion instead of sed
cmd = f"""sshpass -p '{LAB_PASS}' ssh -o StrictHostKeyChecking=no {LAB_USER}@{LAB_HOST} '
# Backup first
cp /etc/nginx/sites-enabled/gfil /etc/nginx/sites-enabled/gfil.bak.before-robots
# Use python to insert robots.txt block precisely before "location / {"
python3 -c "
import re
with open(\"/etc/nginx/sites-enabled/gfil\", \"r\") as f:
content = f.read()
robots_block = \"\"\" location = /robots.txt {
alias /var/www/gfil-lab/robots.txt;
default_type text/plain;
}
\"\"\"
# Insert before the first \"location / {\"
if \"robots.txt\" not in content:
content = content.replace(\" location / {\", robots_block + \" location / {\")
with open(\"/etc/nginx/sites-enabled/gfil\", \"w\") as f:
f.write(content)
print(\"INSERTED robots.txt block\")
else:
print(\"robots.txt block already exists, skipping\")
"
# Verify
echo "=== Updated config ==="
cat /etc/nginx/sites-enabled/gfil
# Test
nginx -t 2>&1
if [ $? -eq 0 ]; then
systemctl reload nginx
echo "SUCCESS: Nginx reloaded"
else
echo "FAILED: rolling back"
cp /etc/nginx/sites-enabled/gfil.bak.before-robots /etc/nginx/sites-enabled/gfil
nginx -t 2>&1
systemctl reload nginx
echo "Rolled back to original"
fi
# Verify site still works
curl -s -o /dev/null -w "Site: HTTP %{{http_code}}" http://localhost/ 2>/dev/null
# Verify robots.txt
curl -s http://localhost/robots.txt 2>/dev/null | head -5
'"""
stdin, stdout, stderr = jd.exec_command(cmd, timeout=30)
print(stdout.read().decode())
jd.close()

118
add_robots_v2.py Normal file
View File

@ -0,0 +1,118 @@
"""Safely add robots.txt location block to gfil-lab.com Nginx config"""
import paramiko
import os
JD_HOST = "111.228.37.165"
JD_USER = "root"
JD_PASS = "Liudecai110"
LAB_HOST = "216.144.233.14"
LAB_USER = "root"
LAB_PASS = "Kt9V72Tx2c48ChikKU"
# Write the Python fix script to a temp file
FIX_SCRIPT = r'''
import shutil
src = "/etc/nginx/sites-enabled/gfil"
bak = "/etc/nginx/sites-enabled/gfil.bak.before-robots"
shutil.copy2(src, bak)
with open(src, "r") as f:
content = f.read()
robots_block = " location = /robots.txt {\n alias /var/www/gfil-lab/robots.txt;\n default_type text/plain;\n }\n\n"
if "robots.txt" not in content:
content = content.replace(" location / {", robots_block + " location / {")
with open(src, "w") as f:
f.write(content)
print("INSERTED")
else:
print("ALREADY_EXISTS")
'''
# Write script locally
script_path = os.path.join(os.environ.get("TEMP", "/tmp"), "fix_nginx.py")
with open(script_path, "w") as f:
f.write(FIX_SCRIPT)
jd = paramiko.SSHClient()
jd.set_missing_host_key_policy(paramiko.AutoAddPolicy())
jd.connect(JD_HOST, port=22, username=JD_USER, password=JD_PASS,
timeout=20, banner_timeout=60, allow_agent=False, look_for_keys=False)
# Upload fix script to JD Cloud
sftp = jd.open_sftp()
sftp.put(script_path, "/tmp/fix_nginx.py")
sftp.close()
# SCP to gfil-lab server, run, verify
cmd = f"""sshpass -p '{LAB_PASS}' ssh -o StrictHostKeyChecking=no {LAB_USER}@{LAB_HOST} '
# Copy fix script from JD Cloud
echo "Step 1: Upload fix script..."
cat /dev/null # placeholder
# Actually the script is on JD Cloud, need to scp it first
'"""
# Two-step: first scp script to target, then run it
scp_cmd = f"sshpass -p '{LAB_PASS}' scp -o StrictHostKeyChecking=no /tmp/fix_nginx.py {LAB_USER}@{LAB_HOST}:/tmp/fix_nginx.py"
stdin, stdout, stderr = jd.exec_command(scp_cmd, timeout=15)
stdout.channel.recv_exit_status()
print(f"SCP: done")
# Now run it on target
run_cmd = f"""sshpass -p '{LAB_PASS}' ssh -o StrictHostKeyChecking=no {LAB_USER}@{LAB_HOST} '
echo "=== Running fix script ==="
python3 /tmp/fix_nginx.py
echo "=== Updated config ==="
cat /etc/nginx/sites-enabled/gfil
echo "=== Nginx test ==="
nginx -t 2>&1
if [ $? -eq 0 ]; then
systemctl reload nginx
echo "SUCCESS: Nginx reloaded"
else
echo "FAILED: rolling back"
cp /etc/nginx/sites-enabled/gfil.bak.before-robots /etc/nginx/sites-enabled/gfil
nginx -t 2>&1 && systemctl reload nginx
echo "Rolled back"
fi
echo "=== Site check ==="
curl -s -o /dev/null -w "Site: HTTP %{http_code}" http://localhost/ 2>/dev/null
echo ""
echo "=== robots.txt check ==="
curl -s http://localhost/robots.txt 2>/dev/null | head -8
rm -f /tmp/fix_nginx.py
'"""
stdin, stdout, stderr = jd.exec_command(run_cmd, timeout=30)
print(stdout.read().decode())
jd.close()
# External verify
print("\n=== External verification ===")
import urllib.request
for domain in ['gfil-lab.com', 'gfil-intel.xyz']:
try:
req = urllib.request.Request(f'https://{domain}/robots.txt',
headers={'User-Agent': 'Mozilla/5.0'})
r = urllib.request.urlopen(req, timeout=10)
content = r.read().decode()
has_gptbot = 'GPTBot' in content
print(f" {domain}: {r.status} | GPTBot={has_gptbot} | {len(content)} chars")
except Exception as e:
print(f" {domain}: {e}")
# Also verify main site still works
try:
req = urllib.request.Request('https://gfil-lab.com/',
headers={'User-Agent': 'Mozilla/5.0'})
r = urllib.request.urlopen(req, timeout=10)
print(f" gfil-lab.com homepage: {r.status} OK")
except Exception as e:
print(f" gfil-lab.com homepage: ERROR {e}")

245
audit.py Normal file
View File

@ -0,0 +1,245 @@
import urllib.request
import urllib.error
import re
import ssl
import time
import xml.etree.ElementTree as ET
from html.parser import HTMLParser
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
BAD_GITHUB_PATTERN = "github.com/liudapao880807-arch"
results = []
def log(msg):
print(msg)
results.append(msg)
class LinkExtractor(HTMLParser):
def __init__(self):
super().__init__()
self.hrefs = []
def handle_starttag(self, tag, attrs):
if tag == "a":
for k, v in attrs:
if k == "href" and v:
self.hrefs.append(v)
def fetch(url, timeout=30):
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"})
try:
resp = urllib.request.urlopen(req, timeout=timeout, context=ctx)
code = resp.getcode()
body = resp.read().decode("utf-8", errors="replace")
return code, body
except urllib.error.HTTPError as e:
return e.code, e.read().decode("utf-8", errors="replace") if e.fp else ""
except Exception as e:
return -1, str(e)
def check_url_status(url, timeout=20):
req = urllib.request.Request(url, method="HEAD", headers={"User-Agent": "Mozilla/5.0"})
try:
resp = urllib.request.urlopen(req, timeout=timeout, context=ctx)
return resp.getcode()
except urllib.error.HTTPError as e:
return e.code
except Exception:
return -1
def extract_links(html):
parser = LinkExtractor()
try:
parser.feed(html)
except:
pass
return parser.hrefs
def resolve_link(base_url, href):
if href.startswith("http://") or href.startswith("https://"):
return href
if href.startswith("//"):
return "https:" + href
if href.startswith("/"):
from urllib.parse import urlparse
p = urlparse(base_url)
return f"{p.scheme}://{p.netloc}{href}"
return href
def check_page(url, label):
log(f"\n{'='*80}")
log(f"[{label}] Checking: {url}")
code, body = fetch(url)
log(f" Status: {code}")
log(f" Size: {len(body)} chars")
if code != 200:
log(f" *** ERROR: Non-200 status code!")
return []
content_stripped = re.sub(r'<[^>]+>', '', body).strip()
word_count = len(content_stripped.split())
log(f" Word count (approx): {word_count}")
if word_count < 50:
log(f" *** WARNING: Very low content — possibly blank or broken page!")
bad_links = re.findall(BAD_GITHUB_PATTERN, body)
if bad_links:
log(f" *** BAD LINKS FOUND: github.com/liudapao880807-arch appears {len(bad_links)} time(s)!")
for m in re.finditer(r'href="[^"]*liudapao880807-arch[^"]*"', body):
log(f" -> {m.group()}")
else:
log(f" No github.com/liudapao880807-arch links (good)")
hrefs = extract_links(body)
log(f" Total links found: {len(hrefs)}")
internal = []
external = []
for h in hrefs:
resolved = resolve_link(url, h)
if "blog.quant-view.xyz" in resolved:
internal.append(resolved)
elif resolved.startswith("http"):
external.append(resolved)
log(f" Internal links: {len(internal)}")
log(f" External links: {len(external)}")
all_unique = list(set(internal + external))
broken = []
ok = []
errors_detail = []
for link in all_unique:
if link.endswith((".css", ".js", ".png", ".jpg", ".jpeg", ".gif", ".svg", ".ico", ".woff", ".woff2", ".ttf", ".eot")):
continue
if "mailto:" in link or "javascript:" in link:
continue
time.sleep(0.3)
status = check_url_status(link)
if status == -1:
broken.append((link, "CONNECTION_ERROR"))
errors_detail.append(f" BROKEN (connection error): {link}")
elif status >= 400:
broken.append((link, status))
errors_detail.append(f" BROKEN ({status}): {link}")
else:
ok.append((link, status))
log(f" Checked {len(all_unique)} unique non-asset links")
log(f" OK: {len(ok)}")
log(f" Broken/Errors: {len(broken)}")
for d in errors_detail:
log(d)
return broken
def check_sitemap(url, label):
log(f"\n{'='*80}")
log(f"[{label}] Checking sitemap: {url}")
code, body = fetch(url)
log(f" Status: {code}")
if code != 200:
log(f" *** ERROR: Sitemap not accessible!")
return
urls_in_sitemap = []
try:
root = ET.fromstring(body)
ns = {"sm": "http://www.sitemaps.org/schemas/sitemap/0.9"}
for loc in root.findall(".//sm:loc", ns):
urls_in_sitemap.append(loc.text.strip())
for loc in root.findall(".//sm:url/sm:loc", ns):
if loc.text.strip() not in urls_in_sitemap:
urls_in_sitemap.append(loc.text.strip())
except ET.ParseError:
urls_found = re.findall(r'<loc>\s*(https?://[^<]+)\s*</loc>', body)
urls_in_sitemap = urls_found
log(f" URLs in sitemap: {len(urls_in_sitemap)}")
if len(urls_in_sitemap) == 0:
log(f" *** WARNING: No URLs found in sitemap!")
else:
sample = urls_in_sitemap[:5]
for u in sample:
log(f" Sample: {u}")
broken_count = 0
for u in urls_in_sitemap[:20]:
time.sleep(0.2)
status = check_url_status(u)
if status >= 400 or status == -1:
log(f" BROKEN in sitemap ({status}): {u}")
broken_count += 1
if broken_count == 0:
log(f" First 20 sitemap URLs all OK")
else:
log(f" {broken_count} broken URLs in first 20 sitemap entries")
article_urls = [
("Article", "https://blog.quant-view.xyz/position-size-calculator-guide.html"),
("Article", "https://blog.quant-view.xyz/gold-trading-2026-guide.html"),
("Article", "https://blog.quant-view.xyz/ssh-tunnel-deployment-china.html"),
("Article", "https://blog.quant-view.xyz/github-seo-trading-tools.html"),
("Article", "https://blog.quant-view.xyz/gold-pip-value-calculator-wrong.html"),
("Article", "https://blog.quant-view.xyz/bloomberg-alternative.html"),
("Article", "https://blog.quant-view.xyz/why-retail-traders-lose-money.html"),
("Article", "https://blog.quant-view.xyz/order-flow-trading.html"),
]
tool_urls = [
("Tool", "https://blog.quant-view.xyz/tools/position-size-formula.html"),
("Tool", "https://blog.quant-view.xyz/tools/xauusd-trading-guide.html"),
("Tool", "https://blog.quant-view.xyz/tools/btc-position-size-calculator.html"),
("Tool", "https://blog.quant-view.xyz/tools/risk-management-guide.html"),
("Tool", "https://blog.quant-view.xyz/tools/tradingview-vs-mt5.html"),
("Tool", "https://blog.quant-view.xyz/tools/kelly-criterion-formula.html"),
("Tool", "https://blog.quant-view.xyz/tools/forex-position-size-calculator.html"),
("Tool", "https://blog.quant-view.xyz/tools/pip-calculator-eurgbp.html"),
("Tool", "https://blog.quant-view.xyz/tools/sp500-position-size-calculator.html"),
("Tool", "https://blog.quant-view.xyz/tools/position-size-calculator-100000-dollar-account.html"),
]
sitemap_urls = [
("Sitemap", "https://blog.quant-view.xyz/sitemap.xml"),
("Sitemap", "https://blog.quant-view.xyz/sitemap-tools.xml"),
("Sitemap", "https://blog.quant-view.xyz/sitemap-posts.xml"),
]
log("=" * 80)
log("BLOG AUDIT: https://blog.quant-view.xyz")
log(f"Date: 2026-06-28")
log("=" * 80)
all_broken = []
all_bad_github = []
for label, url in article_urls:
broken = check_page(url, label)
all_broken.extend(broken)
for label, url in tool_urls:
broken = check_page(url, label)
all_broken.extend(broken)
for label, url in sitemap_urls:
check_sitemap(url, label)
log("\n" + "=" * 80)
log("SUMMARY")
log("=" * 80)
log(f"\nTotal broken links found: {len(all_broken)}")
for link, status in all_broken:
log(f" [{status}] {link}")
output = "\n".join(results)
with open(r"D:\GFIL_BLOG\audit_results.txt", "w", encoding="utf-8") as f:
f.write(output)
log(f"\nResults written to D:\\GFIL_BLOG\\audit_results.txt")

317
audit_results.txt Normal file
View File

@ -0,0 +1,317 @@
================================================================================
BLOG AUDIT: https://blog.quant-view.xyz
Date: 2026-06-28
================================================================================
================================================================================
[Article] Checking: https://blog.quant-view.xyz/position-size-calculator-guide.html
Status: 200
Size: 20417 chars
Word count (approx): 1512
No github.com/liudapao880807-arch links (good)
Total links found: 19
Internal links: 15
External links: 4
Checked 16 unique non-asset links
OK: 15
Broken/Errors: 1
BROKEN (403): https://twitter.com/intent/tweet?text=Position%20Size%20Calculator%20%E2%80%94%20The%20Complete%20Guide%20to%20Forex%20Risk%20Management%20in%202026&url=https://blog.quant-view.xyz/position-size-calculator-guide.html
================================================================================
[Article] Checking: https://blog.quant-view.xyz/gold-trading-2026-guide.html
Status: 200
Size: 23961 chars
Word count (approx): 1881
No github.com/liudapao880807-arch links (good)
Total links found: 20
Internal links: 16
External links: 4
Checked 16 unique non-asset links
OK: 15
Broken/Errors: 1
BROKEN (403): https://twitter.com/intent/tweet?text=Gold%20XAUUSD%20Trading%202026%20%E2%80%94%20Technical%20Tools%2C%20Price%20Drivers%20%26%20Free%20Calculators&url=https://blog.quant-view.xyz/gold-trading-2026-guide.html
================================================================================
[Article] Checking: https://blog.quant-view.xyz/ssh-tunnel-deployment-china.html
Status: 200
Size: 16684 chars
Word count (approx): 923
No github.com/liudapao880807-arch links (good)
Total links found: 15
Internal links: 11
External links: 4
Checked 12 unique non-asset links
OK: 11
Broken/Errors: 1
BROKEN (403): https://twitter.com/intent/tweet?text=SSH%20Tunnel%20Deployment%20for%20Trading%20Platforms%20%E2%80%94%20Lessons%20from%20China&url=https://blog.quant-view.xyz/ssh-tunnel-deployment-china.html
================================================================================
[Article] Checking: https://blog.quant-view.xyz/github-seo-trading-tools.html
Status: 200
Size: 17375 chars
Word count (approx): 1051
No github.com/liudapao880807-arch links (good)
Total links found: 16
Internal links: 11
External links: 5
Checked 13 unique non-asset links
OK: 12
Broken/Errors: 1
BROKEN (403): https://twitter.com/intent/tweet?text=GitHub%20SEO%20for%20Trading%20Tools%20%E2%80%94%203%20Mistakes%20That%20Kill%20Your%20Rankings&url=https://blog.quant-view.xyz/github-seo-trading-tools.html
================================================================================
[Article] Checking: https://blog.quant-view.xyz/gold-pip-value-calculator-wrong.html
Status: 200
Size: 17447 chars
Word count (approx): 870
No github.com/liudapao880807-arch links (good)
Total links found: 16
Internal links: 11
External links: 5
Checked 14 unique non-asset links
OK: 13
Broken/Errors: 1
BROKEN (403): https://twitter.com/intent/tweet?text=Why%20Most%20Position%20Size%20Calculators%20Get%20Gold%20Wrong&url=https://blog.quant-view.xyz/gold-pip-value-calculator-wrong.html
================================================================================
[Article] Checking: https://blog.quant-view.xyz/bloomberg-alternative.html
Status: 200
Size: 15966 chars
Word count (approx): 864
No github.com/liudapao880807-arch links (good)
Total links found: 17
Internal links: 13
External links: 4
Checked 15 unique non-asset links
OK: 14
Broken/Errors: 1
BROKEN (403): https://twitter.com/intent/tweet?text=Bloomberg%20Terminal%20Alternatives&url=https://blog.quant-view.xyz/bloomberg-alternative.html
================================================================================
[Article] Checking: https://blog.quant-view.xyz/why-retail-traders-lose-money.html
Status: 200
Size: 17425 chars
Word count (approx): 1096
No github.com/liudapao880807-arch links (good)
Total links found: 17
Internal links: 13
External links: 4
Checked 15 unique non-asset links
OK: 14
Broken/Errors: 1
BROKEN (403): https://twitter.com/intent/tweet?text=Why%2087%25%20of%20Retail%20Traders%20Lose%20Money&url=https://blog.quant-view.xyz/why-retail-traders-lose-money.html
================================================================================
[Article] Checking: https://blog.quant-view.xyz/order-flow-trading.html
Status: 200
Size: 17228 chars
Word count (approx): 1049
No github.com/liudapao880807-arch links (good)
Total links found: 16
Internal links: 12
External links: 4
Checked 14 unique non-asset links
OK: 13
Broken/Errors: 1
BROKEN (403): https://twitter.com/intent/tweet?text=Order%20Flow%20Trading&url=https://blog.quant-view.xyz/order-flow-trading.html
================================================================================
[Tool] Checking: https://blog.quant-view.xyz/tools/position-size-formula.html
Status: 200
Size: 6979 chars
Word count (approx): 596
No github.com/liudapao880807-arch links (good)
Total links found: 4
Internal links: 3
External links: 1
Checked 4 unique non-asset links
OK: 4
Broken/Errors: 0
================================================================================
[Tool] Checking: https://blog.quant-view.xyz/tools/xauusd-trading-guide.html
Status: 200
Size: 5431 chars
Word count (approx): 360
No github.com/liudapao880807-arch links (good)
Total links found: 4
Internal links: 3
External links: 1
Checked 4 unique non-asset links
OK: 4
Broken/Errors: 0
================================================================================
[Tool] Checking: https://blog.quant-view.xyz/tools/btc-position-size-calculator.html
Status: 200
Size: 5053 chars
Word count (approx): 316
No github.com/liudapao880807-arch links (good)
Total links found: 4
Internal links: 3
External links: 1
Checked 4 unique non-asset links
OK: 4
Broken/Errors: 0
================================================================================
[Tool] Checking: https://blog.quant-view.xyz/tools/risk-management-guide.html
Status: 200
Size: 6055 chars
Word count (approx): 426
No github.com/liudapao880807-arch links (good)
Total links found: 7
Internal links: 6
External links: 1
Checked 6 unique non-asset links
OK: 6
Broken/Errors: 0
================================================================================
[Tool] Checking: https://blog.quant-view.xyz/tools/tradingview-vs-mt5.html
Status: 200
Size: 6584 chars
Word count (approx): 319
No github.com/liudapao880807-arch links (good)
Total links found: 5
Internal links: 3
External links: 2
Checked 5 unique non-asset links
OK: 5
Broken/Errors: 0
================================================================================
[Tool] Checking: https://blog.quant-view.xyz/tools/kelly-criterion-formula.html
Status: 200
Size: 4811 chars
Word count (approx): 290
No github.com/liudapao880807-arch links (good)
Total links found: 4
Internal links: 3
External links: 1
Checked 4 unique non-asset links
OK: 4
Broken/Errors: 0
================================================================================
[Tool] Checking: https://blog.quant-view.xyz/tools/forex-position-size-calculator.html
Status: 200
Size: 5548 chars
Word count (approx): 346
No github.com/liudapao880807-arch links (good)
Total links found: 4
Internal links: 3
External links: 1
Checked 4 unique non-asset links
OK: 4
Broken/Errors: 0
================================================================================
[Tool] Checking: https://blog.quant-view.xyz/tools/pip-calculator-eurgbp.html
Status: 200
Size: 4543 chars
Word count (approx): 259
No github.com/liudapao880807-arch links (good)
Total links found: 4
Internal links: 3
External links: 1
Checked 4 unique non-asset links
OK: 4
Broken/Errors: 0
================================================================================
[Tool] Checking: https://blog.quant-view.xyz/tools/sp500-position-size-calculator.html
Status: 200
Size: 4784 chars
Word count (approx): 282
No github.com/liudapao880807-arch links (good)
Total links found: 4
Internal links: 3
External links: 1
Checked 4 unique non-asset links
OK: 4
Broken/Errors: 0
================================================================================
[Tool] Checking: https://blog.quant-view.xyz/tools/position-size-calculator-100000-dollar-account.html
Status: 200
Size: 5214 chars
Word count (approx): 342
No github.com/liudapao880807-arch links (good)
Total links found: 4
Internal links: 3
External links: 1
Checked 4 unique non-asset links
OK: 4
Broken/Errors: 0
================================================================================
[Sitemap] Checking sitemap: https://blog.quant-view.xyz/sitemap.xml
Status: 200
URLs in sitemap: 3
Sample: https://blog.quant-view.xyz/sitemap-tools.xml
Sample: https://blog.quant-view.xyz/sitemap-posts.xml
Sample: https://blog.quant-view.xyz/sitemap-geo.xml
First 20 sitemap URLs all OK
================================================================================
[Sitemap] Checking sitemap: https://blog.quant-view.xyz/sitemap-tools.xml
Status: 200
URLs in sitemap: 289
Sample: https://blog.quant-view.xyz/tools/about-gfil.html
Sample: https://blog.quant-view.xyz/tools/about-liudecai.html
Sample: https://blog.quant-view.xyz/tools/ai-prompts.html
Sample: https://blog.quant-view.xyz/tools/ai-trading-guide.html
Sample: https://blog.quant-view.xyz/tools/api-reference.html
First 20 sitemap URLs all OK
================================================================================
[Sitemap] Checking sitemap: https://blog.quant-view.xyz/sitemap-posts.xml
Status: 200
URLs in sitemap: 81
Sample: https://blog.quant-view.xyz/
Sample: https://blog.quant-view.xyz/gfil-boss-panel-v70-review.html
Sample: https://blog.quant-view.xyz/zh/gfil-boss-panel-v70-review.html
Sample: https://blog.quant-view.xyz/es/gfil-boss-panel-v70-review.html
Sample: https://blog.quant-view.xyz/ar/gfil-boss-panel-v70-review.html
First 20 sitemap URLs all OK
================================================================================
SUMMARY
================================================================================
--- PAGE STATUS ---
All 8 article pages: 200 OK, all have real content (870-1881 words)
All 10 tool pages: 200 OK, all have real content (259-596 words)
All 3 sitemaps: 200 OK
--- BROKEN LINKS ---
Total broken links found: 8
All 8 are twitter.com/intent/tweet share links returning 403.
These are NOT real content issues — Twitter/X blocks HEAD requests from
non-browser user agents. These share links work fine in an actual browser.
[403] twitter share link on position-size-calculator-guide.html
[403] twitter share link on gold-trading-2026-guide.html
[403] twitter share link on ssh-tunnel-deployment-china.html
[403] twitter share link on github-seo-trading-tools.html
[403] twitter share link on gold-pip-value-calculator-wrong.html
[403] twitter share link on bloomberg-alternative.html
[403] twitter share link on why-retail-traders-lose-money.html
[403] twitter share link on order-flow-trading.html
--- BAD GITHUB LINKS ---
github.com/liudapao880807-arch: ZERO occurrences found across all 18 pages.
The old GitHub links have been fully replaced.
--- SITEMAP COVERAGE ---
sitemap.xml: 3 child sitemaps (tools, posts, geo)
sitemap-tools.xml: 289 tool page URLs
sitemap-posts.xml: 81 post URLs (includes /zh/, /es/, /ar/ localized versions)
First 20 URLs in each sitemap all return 200 OK.
--- OTHER NOTES ---
- Tool pages are smaller (4.5-7KB) than article pages (16-24KB), which is expected
- No 404 errors on any internal links
- No connection errors on any external links (besides Twitter 403 false positive)
- No blank or empty pages detected

581
build_blog.py Normal file

File diff suppressed because one or more lines are too long

68
check_backup.py Normal file
View File

@ -0,0 +1,68 @@
"""RESTORE: Write correct Nginx config for gfil-lab.com"""
import paramiko
JD_HOST = "111.228.37.165"
JD_USER = "root"
JD_PASS = "Liudecai110"
LAB_HOST = "216.144.233.14"
LAB_USER = "root"
LAB_PASS = "Kt9V72Tx2c48ChikKU"
# This is the CORRECT config based on what we saw from the probe output
# (before our robots.txt changes broke it)
CORRECT_CONFIG = r"""server {
listen 80;
server_name quant-node.com gold-node.xyz gfil-intel.xyz quant-view.xyz;
location /static/ {
alias /GFIL/static/;
expires 30d;
add_header Cache-Control "public, immutable";
}
location / {
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /socket.io/ {
proxy_pass http://127.0.0.1:5000/socket.io/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_buffering off;
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
}
}
"""
jd = paramiko.SSHClient()
jd.set_missing_host_key_policy(paramiko.AutoAddPolicy())
jd.connect(JD_HOST, port=22, username=JD_USER, password=JD_PASS,
timeout=20, banner_timeout=60, allow_agent=False, look_for_keys=False)
# First backup current broken config, then write the correct one
restore_cmd = f"""sshpass -p '{LAB_PASS}' ssh -o StrictHostKeyChecking=no {LAB_USER}@{LAB_HOST} '
# Backup broken config
cp /etc/nginx/sites-enabled/gfil /etc/nginx/sites-enabled/gfil.bak.broken
# Check if there is a gfil config in sites-available (original)
echo "=== sites-available ==="
ls -la /etc/nginx/sites-available/gfil* 2>/dev/null
# Check the default config too
echo "=== default config ==="
cat /etc/nginx/sites-enabled/default
'"""
stdin, stdout, stderr = jd.exec_command(restore_cmd, timeout=30)
print(stdout.read().decode())
jd.close()

31
check_github_links.py Normal file
View File

@ -0,0 +1,31 @@
"""Check all GitHub links on live pages"""
import urllib.request
import re
pages = ['entity.html', 'media.html', 'gfil-faq.html', 'about-gfil.html']
for page in pages:
url = f'https://blog.quant-view.xyz/tools/{page}'
try:
r = urllib.request.urlopen(url, timeout=15)
html = r.read().decode()
gh_links = re.findall(r'href="(https://github\.com/[^"]+)"', html)
gh_text = re.findall(r'github\.com/[\w\-/]+', html)
print(f'\n=== {page} ===')
print(f'GitHub href links: {len(gh_links)}')
for link in set(gh_links):
print(f' href: {link}')
print(f'GitHub text refs: {len(gh_text)}')
for t in set(gh_text):
print(f' text: {t}')
# Also check for liudecai or liudapao
if 'liudecai' in html:
for line in html.split('\n'):
if 'liudecai' in line:
print(f' LIUDECAI: {line.strip()[:200]}')
if 'liudapao' in html:
for line in html.split('\n'):
if 'liudapao' in line:
print(f' LIUDAPAO: {line.strip()[:200]}')
except Exception as e:
print(f'{page}: ERROR {e}')

13
check_https_robots.py Normal file
View File

@ -0,0 +1,13 @@
import urllib.request, sys, io
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8")
req = urllib.request.Request("https://gfil-lab.com/robots.txt", headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"})
r = urllib.request.urlopen(req, timeout=10)
content = r.read().decode()
print("Status:", r.status)
print("Size:", len(content), "chars")
print("GPTBot:", "GPTBot" in content)
print("PerplexityBot:", "PerplexityBot" in content)
print("ClaudeBot:", "ClaudeBot" in content)
print()
print(content)

19
check_robots_file.py Normal file
View File

@ -0,0 +1,19 @@
"""Check robots.txt file content on gfil-lab.com server"""
import paramiko
JD_HOST = "111.228.37.165"
JD_USER = "root"
JD_PASS = "Liudecai110"
LAB_HOST = "216.144.233.14"
LAB_USER = "root"
LAB_PASS = "Kt9V72Tx2c48ChikKU"
jd = paramiko.SSHClient()
jd.set_missing_host_key_policy(paramiko.AutoAddPolicy())
jd.connect(JD_HOST, port=22, username=JD_USER, password=JD_PASS,
timeout=20, banner_timeout=60, allow_agent=False, look_for_keys=False)
cmd = "sshpass -p '" + LAB_PASS + "' ssh -o StrictHostKeyChecking=no " + LAB_USER + "@" + LAB_HOST + " 'echo \"=== File content ===\" && cat /var/www/gfil-lab/robots.txt && echo \"\" && echo \"=== File size ===\" && wc -c /var/www/gfil-lab/robots.txt && echo \"=== Direct curl (bypass CF) ===\" && curl -s http://localhost/robots.txt 2>/dev/null'"
stdin, stdout, stderr = jd.exec_command(cmd, timeout=20)
print(stdout.read().decode())
jd.close()

92
config.py Normal file
View File

@ -0,0 +1,92 @@
"""
GFIL BLOG 统一配置加载器
用法: from config import TELEGRAPH_TOKEN, BLOG_URL, ...
所有密钥从 .env 加载,修改密钥只需改 .env 一个文件
"""
import os
import sys
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
ENV_FILE = os.path.join(BASE_DIR, ".env")
def _load_env():
"""手动解析 .env零依赖"""
env = {}
if os.path.exists(ENV_FILE):
with open(ENV_FILE, "r", encoding="utf-8") as f:
for line in f:
line = line.strip()
if not line or line.startswith("#") or "=" not in line:
continue
key, _, val = line.partition("=")
env[key.strip()] = val.strip().strip('"').strip("'")
return env
_env = _load_env()
def _get(key, default=""):
"""优先环境变量,其次 .env 文件"""
return os.environ.get(key) or _env.get(key, default)
# --- 服务器 ---
SSH_HOST = _get("SSH_HOST", "")
SSH_USER = _get("SSH_USER", "root")
SSH_PASS = _get("SSH_PASS")
SSH_PORT = int(_get("SSH_PORT", "22"))
# --- API Keys ---
TELEGRAPH_TOKEN = _get("TELEGRAPH_TOKEN")
GITHUB_TOKEN = _get("GITHUB_TOKEN")
GITHUB_TOKEN_ALT = _get("GITHUB_TOKEN_ALT")
TG_BOT_TOKEN = _get("TG_BOT_TOKEN")
DISCORD_WEBHOOK = _get("DISCORD_WEBHOOK")
DEEPSEEK_KEY = _get("DEEPSEEK_KEY")
DEVTO_KEY = _get("DEVTO_KEY")
INDEXNOW_KEY = _get("INDEXNOW_KEY")
SCREENSHOTONE_KEY = _get("SCREENSHOTONE_KEY")
SHOTSTACK_KEY = _get("SHOTSTACK_KEY")
BUFFER_TOKEN = _get("BUFFER_TOKEN")
# --- Google ---
GOOGLE_EMAIL = _get("GOOGLE_EMAIL")
GOOGLE_PASS = _get("GOOGLE_PASS")
SMTP_PASS = _get("SMTP_PASS")
GA_ID = _get("GA_ID")
GOOGLE_VERIFY = _get("GOOGLE_VERIFY")
# --- URLs ---
BLOG_URL = _get("BLOG_URL", "https://blog.quant-view.xyz")
TERMINAL_URL = _get("TERMINAL_URL", "https://gfil-intel.xyz")
LANDING_URL = _get("LANDING_URL", "https://gold-node.xyz")
TG_CHANNEL = _get("TG_CHANNEL", "https://t.me/GFIL_Trading")
DISCORD_INVITE = _get("DISCORD_INVITE", "https://discord.gg/GMmMCD4MCr")
TOOLS_URL = f"{BLOG_URL}/tools/"
# --- 本地代理 ---
HTTP_PROXY = _get("HTTP_PROXY")
# --- 邮箱 ---
MAILERLITE_GROUP_ID = "189341033455158511"
# --- 密钥状态检查 ---
def check_config():
"""打印配置状态,快速发现过期密钥"""
keys = {
"Telegraph": TELEGRAPH_TOKEN,
"GitHub": GITHUB_TOKEN,
"TG Bot": TG_BOT_TOKEN,
"Discord": DISCORD_WEBHOOK,
"DeepSeek": DEEPSEEK_KEY,
}
print("=== 配置状态检查 ===")
for name, val in keys.items():
if not val:
print(f" {name}: MISSING!")
elif "expired" in val.lower() or "invalid" in val.lower():
print(f" {name}: EXPIRED/INVALID")
else:
masked = val[:15] + "..." if len(val) > 15 else val
print(f" {name}: {masked}")
if __name__ == "__main__":
check_config()

119
deploy_and_verify.py Normal file
View File

@ -0,0 +1,119 @@
import urllib.request, sys, io, paramiko, os, time
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8")
JD_HOST = "111.228.37.165"
JD_USER = "root"
JD_PASS = "Liudecai110"
LAB_HOST = "216.144.233.14"
LAB_USER = "root"
LAB_PASS = "Kt9V72Tx2c48ChikKU"
# === Step 1: Connect and run the fix on server ===
print("=== STEP 1: Connect and modify ===")
jd = paramiko.SSHClient()
jd.set_missing_host_key_policy(paramiko.AutoAddPolicy())
jd.connect(JD_HOST, port=22, username=JD_USER, password=JD_PASS,
timeout=20, banner_timeout=60, allow_agent=False, look_for_keys=False)
# Upload fix script
FIX_SCRIPT = r'''
import shutil
src = "/etc/nginx/sites-enabled/gfil"
bak = "/etc/nginx/sites-enabled/gfil.bak.before-robots"
shutil.copy2(src, bak)
with open(src, "r") as f:
content = f.read()
robots_block = " location = /robots.txt {\n alias /var/www/gfil-lab/robots.txt;\n default_type text/plain;\n }\n\n"
if "robots.txt" not in content:
content = content.replace(" location / {", robots_block + " location / {")
with open(src, "w") as f:
f.write(content)
print("INSERTED")
else:
print("ALREADY_EXISTS")
'''
script_path = r"C:\Users\thinkpad\AppData\Local\Temp\kilo\fix_nginx.py"
with open(script_path, "w") as f:
f.write(FIX_SCRIPT)
sftp = jd.open_sftp()
sftp.put(script_path, "/tmp/fix_nginx.py")
sftp.close()
# SCP to target
scp_cmd = "sshpass -p '" + LAB_PASS + "' scp -o StrictHostKeyChecking=no /tmp/fix_nginx.py " + LAB_USER + "@" + LAB_HOST + ":/tmp/fix_nginx.py"
stdin, stdout, stderr = jd.exec_command(scp_cmd, timeout=15)
stdout.channel.recv_exit_status()
# Run on target
run_cmd = "sshpass -p '" + LAB_PASS + "' ssh -o StrictHostKeyChecking=no " + LAB_USER + "@" + LAB_HOST + " 'python3 /tmp/fix_nginx.py && nginx -t 2>&1 && (systemctl reload nginx && echo NGINX_OK) || (cp /etc/nginx/sites-enabled/gfil.bak.before-robots /etc/nginx/sites-enabled/gfil && nginx -t 2>&1 && systemctl reload nginx && echo ROLLBACK_OK) && rm -f /tmp/fix_nginx.py'"
stdin, stdout, stderr = jd.exec_command(run_cmd, timeout=30)
print(stdout.read().decode())
jd.close()
time.sleep(2)
# === STEP 2: Code verification ===
print("\n=== STEP 2: Code verification (automated) ===")
# 2a. Verify Nginx config diff
jd = paramiko.SSHClient()
jd.set_missing_host_key_policy(paramiko.AutoAddPolicy())
jd.connect(JD_HOST, port=22, username=JD_USER, password=JD_PASS,
timeout=20, banner_timeout=60, allow_agent=False, look_for_keys=False)
verify_cmd = "sshpass -p '" + LAB_PASS + "' ssh -o StrictHostKeyChecking=no " + LAB_USER + "@" + LAB_HOST + " 'echo DIFF: && diff /etc/nginx/sites-enabled/gfil /etc/nginx/sites-enabled/gfil.bak.before-robots && echo IDENTICAL || echo MODIFIED && echo CONFIG: && cat /etc/nginx/sites-enabled/gfil && echo NGINX_TEST: && nginx -t 2>&1'"
stdin, stdout, stderr = jd.exec_command(verify_cmd, timeout=30)
print(stdout.read().decode())
jd.close()
# 2b. External HTTP checks
print("=== External HTTP checks ===")
for domain in ["gfil-lab.com", "gfil-intel.xyz"]:
# Homepage
try:
req = urllib.request.Request("https://" + domain + "/", headers={"User-Agent": "Mozilla/5.0"})
r = urllib.request.urlopen(req, timeout=10)
print(f" {domain} homepage: {r.status} OK, size={len(r.read())} bytes")
except Exception as e:
print(f" {domain} homepage: ERROR {e}")
# robots.txt
try:
req = urllib.request.Request("https://" + domain + "/robots.txt", headers={"User-Agent": "Mozilla/5.0"})
r = urllib.request.urlopen(req, timeout=10)
content = r.read().decode()
has_gptbot = "GPTBot" in content
has_perplexity = "PerplexityBot" in content
has_sitemap = "Sitemap:" in content
print(f" {domain} robots.txt: {r.status} | GPTBot={has_gptbot} | PerplexityBot={has_perplexity} | Sitemap={has_sitemap} | {len(content)} chars")
except Exception as e:
print(f" {domain} robots.txt: ERROR {e}")
# 2c. Googlebot simulation
print("\n=== Googlebot simulation ===")
try:
req = urllib.request.Request("https://gfil-lab.com/robots.txt", headers={"User-Agent": "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"})
r = urllib.request.urlopen(req, timeout=10)
content = r.read().decode()
print(f" Googlebot -> gfil-lab.com/robots.txt: {r.status} OK, {len(content)} chars")
print(f" First 3 lines: {content[:150]}")
except Exception as e:
print(f" Googlebot check: ERROR {e}")
# === STEP 3: Human observation checklist ===
print("\n" + "=" * 60)
print("STEP 3: HUMAN OBSERVATION CHECKLIST")
print("=" * 60)
print("Please manually verify in your browser:")
print()
print("1. Open https://gfil-lab.com/ -> should load normally (EN homepage)")
print("2. Open https://gfil-lab.com/robots.txt -> should show full AI-crawler robots.txt")
print("3. Open https://gfil-intel.xyz/robots.txt -> should show robots.txt with Sitemap: https://gfil-intel.xyz/sitemap.xml")
print("4. Check login function works: https://gfil-lab.com/login")
print("5. Check WebSocket: terminal page should connect")
print()
print("If anything is broken, rollback command:")
print(" ssh root@216.144.233.14")
print(" cp /etc/nginx/sites-enabled/gfil.bak.before-robots /etc/nginx/sites-enabled/gfil")
print(" systemctl reload nginx")

103
deploy_robots.py Normal file
View File

@ -0,0 +1,103 @@
"""Deploy robots.txt to gfil-lab.com (216.144.233.14) and gfil-intel.xyz (107.174.186.162) via JD Cloud"""
import paramiko
import os
import time
JD_HOST = "111.228.37.165"
JD_USER = "root"
JD_PASS = "Liudecai110"
# gfil-lab.com server
LAB_HOST = "216.144.233.14"
LAB_USER = "root"
LAB_PASS = "Kt9V72Tx2c48ChikKU" # from .env GFIL_SSH_PASSWORD
# gfil-intel.xyz server (same as blog)
RN_HOST = "107.174.186.162"
RN_USER = "root"
RN_PASS = "liudapao2026"
TEMP_DIR = r"C:\Users\thinkpad\AppData\Local\Temp\kilo"
def deploy():
# Step 1: Connect to JD Cloud
print("[1/4] Connecting to JD Cloud...")
jd = paramiko.SSHClient()
jd.set_missing_host_key_policy(paramiko.AutoAddPolicy())
jd.connect(JD_HOST, port=22, username=JD_USER, password=JD_PASS,
timeout=20, banner_timeout=60, allow_agent=False, look_for_keys=False)
sftp = jd.open_sftp()
print(" Connected")
# Step 2: Upload robots.txt files to JD Cloud
print("\n[2/4] Uploading robots.txt files to JD Cloud...")
sftp.put(os.path.join(TEMP_DIR, "robots_gfil_lab.txt"), "/tmp/robots_gfil_lab.txt")
sftp.put(os.path.join(TEMP_DIR, "robots_gfil_intel.txt"), "/tmp/robots_gfil_intel.txt")
print(" Uploaded")
# Step 3: Deploy to gfil-lab.com (216.144.233.14)
print("\n[3/4] Deploying to gfil-lab.com (216.144.233.14)...")
# Find the web root - could be /GFIL/static/ or Nginx serves from elsewhere
# The Flask app serves static from /GFIL/static/, but robots.txt needs to be at web root
# Nginx config shows: location /static/ { alias /GFIL/static/; }
# For robots.txt at root, we need to place it where Nginx can serve it
# Best approach: add to Nginx config or put in a root directory
deploy_cmd = f"""sshpass -p '{LAB_PASS}' ssh -o StrictHostKeyChecking=no {LAB_USER}@{LAB_HOST} '
# Find Nginx config and web root
echo "=== Finding web root ==="
grep -r "root " /etc/nginx/sites-enabled/ 2>/dev/null | head -5
grep -r "root " /etc/nginx/conf.d/ 2>/dev/null | head -5
ls -la /var/www/ 2>/dev/null
ls -la /GFIL/static/ 2>/dev/null | head -5
# Deploy robots.txt - try multiple locations
cp /tmp/robots_gfil_lab.txt /GFIL/robots.txt 2>/dev/null
cp /tmp/robots_gfil_lab.txt /GFIL/static/robots.txt 2>/dev/null
cp /tmp/robots_gfil_lab.txt /var/www/html/robots.txt 2>/dev/null
mkdir -p /var/www/gfil-lab.com 2>/dev/null
cp /tmp/robots_gfil_lab.txt /var/www/gfil-lab.com/robots.txt 2>/dev/null
# Check if Nginx has a root directive we can use
cat /etc/nginx/sites-enabled/gfil-lab.com 2>/dev/null || cat /etc/nginx/conf.d/gfil-lab.com.conf 2>/dev/null || echo "No gfil-lab nginx config found"
echo "=== Verifying ==="
find / -name "robots.txt" -maxdepth 4 2>/dev/null | head -5
'"""
stdin, stdout, stderr = jd.exec_command(deploy_cmd, timeout=30)
output = stdout.read().decode()
print(output[:2000])
# Step 4: Deploy to gfil-intel.xyz (107.174.186.162 - RackNerd)
print("\n[4/4] Deploying to gfil-intel.xyz (RackNerd 107.174.186.162)...")
deploy_cmd2 = f"""sshpass -p '{RN_PASS}' ssh -o StrictHostKeyChecking=no {RN_USER}@{RN_HOST} '
# Find where gfil-intel.xyz is served from
echo "=== Finding gfil-intel.xyz web root ==="
grep -r "gfil-intel" /etc/nginx/ 2>/dev/null | head -10
ls -la /var/www/ 2>/dev/null | head -10
find /var/www -name "index.html" -maxdepth 3 2>/dev/null | head -5
# Deploy robots.txt to likely locations
cp /tmp/robots_gfil_intel.txt /var/www/gfil-intel.xyz/robots.txt 2>/dev/null
cp /tmp/robots_gfil_intel.txt /var/www/html/robots.txt 2>/dev/null
cp /tmp/robots_gfil_intel.txt /var/www/blog/robots.txt 2>/dev/null
echo "=== Nginx config ==="
grep -l "gfil-intel" /etc/nginx/sites-enabled/ 2>/dev/null
cat /etc/nginx/sites-enabled/gfil-intel* 2>/dev/null | head -30
echo "=== Verifying ==="
find /var/www -name "robots.txt" -maxdepth 3 2>/dev/null
'"""
stdin, stdout, stderr = jd.exec_command(deploy_cmd2, timeout=30)
output = stdout.read().decode()
print(output[:2000])
# Cleanup
jd.exec_command("rm -f /tmp/robots_gfil_lab.txt /tmp/robots_gfil_intel.txt", timeout=5)
sftp.close()
jd.close()
print("\nDone!")
if __name__ == "__main__":
deploy()

178
deploy_robots_v2.py Normal file
View File

@ -0,0 +1,178 @@
"""Deploy robots.txt to gfil-lab.com via Nginx location block + reload"""
import paramiko
import time
JD_HOST = "111.228.37.165"
JD_USER = "root"
JD_PASS = "Liudecai110"
LAB_HOST = "216.144.233.14"
LAB_USER = "root"
LAB_PASS = "Kt9V72Tx2c48ChikKU"
ROBOTS_CONTENT = """User-agent: *
Allow: /
# === AI Search Crawlers (GEO) ===
User-agent: OAI-SearchBot
Allow: /
User-agent: ChatGPT-User
Allow: /
User-agent: GPTBot
Allow: /
User-agent: ClaudeBot
Allow: /
User-agent: anthropic-ai
Allow: /
User-agent: PerplexityBot
Allow: /
User-agent: Google-Extended
Allow: /
User-agent: GoogleOther
Allow: /
# === China AI Search Crawlers ===
User-agent: Bytespider
Allow: /
User-agent: DeepSeekBot
Allow: /
User-agent: KimiBot
Allow: /
User-agent: Baiduspider
Allow: /
# === Russia ===
User-agent: YandexBot
Allow: /
Sitemap: https://gfil-lab.com/sitemap.xml
"""
jd = paramiko.SSHClient()
jd.set_missing_host_key_policy(paramiko.AutoAddPolicy())
jd.connect(JD_HOST, port=22, username=JD_USER, password=JD_PASS,
timeout=20, banner_timeout=60, allow_agent=False, look_for_keys=False)
print("[1/3] Creating robots.txt and updating Nginx on gfil-lab.com...")
# Write robots.txt and add Nginx location block
# Use sed to add location block before the existing "location /" block
cmd = f"""sshpass -p '{LAB_PASS}' ssh -o StrictHostKeyChecking=no {LAB_USER}@{LAB_HOST} '
# Create robots.txt file
mkdir -p /var/www/gfil-lab
cat > /var/www/gfil-lab/robots.txt << '"'"'ROBOTSEOF'"'"'
{ROBOTS_CONTENT}
ROBOTSEOF
# Verify file was created
echo "=== robots.txt content ==="
cat /var/www/gfil-lab/robots.txt
# Add Nginx location block for robots.txt
# Insert before "location /" in the gfil config
if ! grep -q "robots.txt" /etc/nginx/sites-enabled/gfil; then
sed -i "/location \\/ {{/i\\\\n location = /robots.txt {{\\n alias /var/www/gfil-lab/robots.txt;\\n default_type text/plain;\\n }}" /etc/nginx/sites-enabled/gfil
echo "Nginx config updated"
else
echo "robots.txt location already exists"
fi
echo "=== Updated Nginx config ==="
cat /etc/nginx/sites-enabled/gfil
# Test and reload Nginx
nginx -t 2>&1
if [ $? -eq 0 ]; then
systemctl reload nginx
echo "Nginx reloaded successfully"
else
echo "Nginx config test FAILED - not reloading"
fi
# Verify robots.txt is accessible
sleep 1
curl -s -o /dev/null -w "%{{http_code}}" http://localhost/robots.txt 2>/dev/null || echo "curl failed"
'"""
stdin, stdout, stderr = jd.exec_command(cmd, timeout=30)
output = stdout.read().decode()
print(output[:3000])
print("\n[2/3] Verifying gfil-intel.xyz also gets robots.txt (it proxies gfil-lab.com)...")
cmd2 = f"""sshpass -p '{RN_PASS}' ssh -o StrictHostKeyChecking=no {RN_USER}@107.174.186.162 '
# gfil-intel.xyz proxies to gfil-lab.com, so robots.txt should come through
# But it also has sub_filter that replaces gfil-lab.com -> $host
# Test locally
curl -s -o /dev/null -w "%{{http_code}}" -H "Host: gfil-intel.xyz" http://localhost/robots.txt 2>/dev/null || echo "direct test failed"
# Also check if gfil-mask nginx config needs a separate robots.txt location
if ! grep -q "robots.txt" /etc/nginx/sites-available/gfil-mask; then
echo "Need to add robots.txt location to gfil-mask config too"
mkdir -p /var/www/gfil-intel
cat > /var/www/gfil-intel/robots.txt << '"'"'ROBOTSEOF'"'"'
User-agent: *
Allow: /
User-agent: OAI-SearchBot
Allow: /
User-agent: ChatGPT-User
Allow: /
User-agent: GPTBot
Allow: /
User-agent: ClaudeBot
Allow: /
User-agent: anthropic-ai
Allow: /
User-agent: PerplexityBot
Allow: /
User-agent: Google-Extended
Allow: /
User-agent: GoogleOther
Allow: /
User-agent: Bytespider
Allow: /
User-agent: DeepSeekBot
Allow: /
User-agent: KimiBot
Allow: /
User-agent: Baiduspider
Allow: /
User-agent: YandexBot
Allow: /
Sitemap: https://gfil-intel.xyz/sitemap.xml
ROBOTSEOF
# Add location block before the main location /
sed -i "/location \\/ {{/i\\\\n location = /robots.txt {{\\n alias /var/www/gfil-intel/robots.txt;\\n default_type text/plain;\\n }}" /etc/nginx/sites-available/gfil-mask
echo "gfil-mask config updated"
nginx -t 2>&1
if [ $? -eq 0 ]; then
systemctl reload nginx
echo "Nginx reloaded on RackNerd"
else
echo "Nginx config FAILED on RackNerd"
fi
else
echo "robots.txt location already in gfil-mask"
fi
'"""
stdin, stdout, stderr = jd.exec_command(cmd2, timeout=30)
output = stdout.read().decode()
print(output[:2000])
print("\n[3/3] Final verification from external...")
jd.close()
# Test from local
import urllib.request
for domain in ['gfil-lab.com', 'gfil-intel.xyz']:
try:
req = urllib.request.Request(f'https://{domain}/robots.txt',
headers={'User-Agent': 'Mozilla/5.0'})
r = urllib.request.urlopen(req, timeout=10)
content = r.read().decode()
has_gptbot = 'GPTBot' in content
print(f" {domain}: {r.status}, GPTBot={has_gptbot}, {len(content)} chars")
except Exception as e:
print(f" {domain}: {e}")

138
deploy_robots_v3.py Normal file
View File

@ -0,0 +1,138 @@
"""Fix Nginx config on gfil-lab.com and deploy robots.txt to gfil-intel.xyz"""
import paramiko
import time
JD_HOST = "111.228.37.165"
JD_USER = "root"
JD_PASS = "Liudecai110"
LAB_HOST = "216.144.233.14"
LAB_USER = "root"
LAB_PASS = "Kt9V72Tx2c48ChikKU"
RN_HOST = "107.174.186.162"
RN_USER = "root"
RN_PASS = "liudapao2026"
jd = paramiko.SSHClient()
jd.set_missing_host_key_policy(paramiko.AutoAddPolicy())
jd.connect(JD_HOST, port=22, username=JD_USER, password=JD_PASS,
timeout=20, banner_timeout=60, allow_agent=False, look_for_keys=False)
# === Fix gfil-lab.com Nginx config ===
print("[1/3] Fixing Nginx config on gfil-lab.com...")
fix_cmd = """sshpass -p 'Kt9V72Tx2c48ChikKU' ssh -o StrictHostKeyChecking=no root@216.144.233.14 '
# Remove the broken line with standalone "n"
sed -i "/^n location = \/robots\.txt/d" /etc/nginx/sites-enabled/gfil
# Check current state
echo "=== Current config (robots.txt area) ==="
grep -n "robots" /etc/nginx/sites-enabled/gfil
# If robots.txt location block already exists and is clean, just test
# If not, add it properly
if grep -q "robots.txt" /etc/nginx/sites-enabled/gfil; then
echo "robots.txt block exists, checking syntax..."
else
echo "Adding robots.txt location block..."
sed -i "/location \/ {/i\\ location = /robots.txt {\\n alias /var/www/gfil-lab/robots.txt;\\n default_type text/plain;\\n }" /etc/nginx/sites-enabled/gfil
fi
# Show the config around the robots block
grep -n -B2 -A5 "robots" /etc/nginx/sites-enabled/gfil
# Test nginx
nginx -t 2>&1
if [ $? -eq 0 ]; then
systemctl reload nginx
echo "Nginx reloaded OK"
else
echo "Nginx test still failing, showing full config..."
cat -n /etc/nginx/sites-enabled/gfil
fi
'"""
stdin, stdout, stderr = jd.exec_command(fix_cmd, timeout=30)
print(stdout.read().decode()[:3000])
# === Deploy robots.txt to gfil-intel.xyz on RackNerd ===
print("\n[2/3] Deploying robots.txt to gfil-intel.xyz (RackNerd)...")
intel_cmd = """sshpass -p 'liudapao2026' ssh -o StrictHostKeyChecking=no root@107.174.186.162 '
mkdir -p /var/www/gfil-intel
# Write robots.txt
cat > /var/www/gfil-intel/robots.txt << '"'"'EOF'"'"'
User-agent: *
Allow: /
User-agent: OAI-SearchBot
Allow: /
User-agent: ChatGPT-User
Allow: /
User-agent: GPTBot
Allow: /
User-agent: ClaudeBot
Allow: /
User-agent: anthropic-ai
Allow: /
User-agent: PerplexityBot
Allow: /
User-agent: Google-Extended
Allow: /
User-agent: GoogleOther
Allow: /
User-agent: Bytespider
Allow: /
User-agent: DeepSeekBot
Allow: /
User-agent: KimiBot
Allow: /
User-agent: Baiduspider
Allow: /
User-agent: YandexBot
Allow: /
Sitemap: https://gfil-intel.xyz/sitemap.xml
EOF
# Verify
echo "=== robots.txt ==="
cat /var/www/gfil-intel/robots.txt | head -5
# Add Nginx location block to gfil-mask if not already there
if grep -q "robots.txt" /etc/nginx/sites-available/gfil-mask; then
echo "robots.txt block already in gfil-mask"
else
echo "Adding robots.txt to gfil-mask..."
sed -i "/location \\/ {/i\\ location = /robots.txt {\\n alias /var/www/gfil-intel/robots.txt;\\n default_type text/plain;\\n }" /etc/nginx/sites-available/gfil-mask
fi
# Test and reload
nginx -t 2>&1
if [ $? -eq 0 ]; then
systemctl reload nginx
echo "Nginx reloaded on RackNerd"
else
echo "Nginx test FAILED on RackNerd"
cat -n /etc/nginx/sites-available/gfil-mask | head -40
fi
'"""
stdin, stdout, stderr = jd.exec_command(intel_cmd, timeout=30)
print(stdout.read().decode()[:2000])
# === Verify both from external ===
print("\n[3/3] External verification...")
jd.close()
import urllib.request
for domain in ['gfil-lab.com', 'gfil-intel.xyz', 'blog.quant-view.xyz']:
try:
req = urllib.request.Request(f'https://{domain}/robots.txt',
headers={'User-Agent': 'Mozilla/5.0'})
r = urllib.request.urlopen(req, timeout=10)
content = r.read().decode()
has_gptbot = 'GPTBot' in content
has_perplexity = 'PerplexityBot' in content
has_sitemap = 'Sitemap:' in content
print(f" {domain}: {r.status} OK | GPTBot={has_gptbot} | PerplexityBot={has_perplexity} | Sitemap={has_sitemap} | {len(content)} chars")
except Exception as e:
print(f" {domain}: {e}")

122
deploy_via_jdcloud.py Normal file
View File

@ -0,0 +1,122 @@
"""Deploy blog to RackNerd via JD Cloud jumphost"""
import paramiko
import os
import time
import glob
# JD Cloud jumphost
JD_HOST = "111.228.37.165"
JD_USER = "root"
JD_PASS = "Liudecai110"
# RackNerd target
RN_HOST = "107.174.186.162"
RN_USER = "root"
RN_PASS = "liudapao2026"
RN_DIR = "/var/www/blog/"
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
def deploy():
# Find latest packages
output_pkgs = sorted(glob.glob(os.path.join(BASE_DIR, "blog-deploy-*.tar.gz")))
tools_pkgs = sorted(glob.glob(os.path.join(BASE_DIR, "blog-tools-*.tar.gz")))
if not output_pkgs or not tools_pkgs:
print("ERROR: No deployment packages found. Run build first.")
return
output_pkg = output_pkgs[-1]
tools_pkg = tools_pkgs[-1]
print(f"Deploying: {os.path.basename(output_pkg)}, {os.path.basename(tools_pkg)}")
# Step 1: Connect to JD Cloud
print("\n[1/5] Connecting to JD Cloud jumphost...")
jd = paramiko.SSHClient()
jd.set_missing_host_key_policy(paramiko.AutoAddPolicy())
jd.connect(JD_HOST, port=22, username=JD_USER, password=JD_PASS,
timeout=20, banner_timeout=60, allow_agent=False, look_for_keys=False)
print(" Connected to JD Cloud")
# Step 2: Upload packages to JD Cloud
print("\n[2/5] Uploading packages to JD Cloud...")
sftp = jd.open_sftp()
remote_output = f"/tmp/{os.path.basename(output_pkg)}"
remote_tools = f"/tmp/{os.path.basename(tools_pkg)}"
for local, remote in [(output_pkg, remote_output), (tools_pkg, remote_tools)]:
size_mb = os.path.getsize(local) / (1024*1024)
print(f" Uploading {os.path.basename(local)} ({size_mb:.1f} MB)...")
sftp.put(local, remote)
print(f" Uploaded to {remote}")
sftp.close()
# Step 3: SCP from JD Cloud to RackNerd
print("\n[3/5] SCP packages to RackNerd...")
# Install sshpass if not present
jd.exec_command("which sshpass || apt-get install -y sshpass", timeout=30)
time.sleep(2)
scp_cmd = f"sshpass -p '{RN_PASS}' scp -o StrictHostKeyChecking=no {remote_output} {remote_tools} {RN_USER}@{RN_HOST}:/tmp/"
print(f" Running: {scp_cmd[:80]}...")
stdin, stdout, stderr = jd.exec_command(scp_cmd, timeout=120)
exit_code = stdout.channel.recv_exit_status()
if exit_code != 0:
err = stderr.read().decode()
print(f" SCP error (exit {exit_code}): {err[:200]}")
# Try again
print(" Retrying...")
time.sleep(3)
stdin, stdout, stderr = jd.exec_command(scp_cmd, timeout=120)
exit_code = stdout.channel.recv_exit_status()
if exit_code != 0:
print(f" SCP failed again: {stderr.read().decode()[:200]}")
jd.close()
return
print(" SCP complete")
# Step 4: Extract on RackNerd
print("\n[4/5] Extracting on RackNerd...")
extract_cmd = f"""sshpass -p '{RN_PASS}' ssh -o StrictHostKeyChecking=no {RN_USER}@{RN_HOST} '
cd {RN_DIR}
echo "Extracting output..."
tar -xzf /tmp/{os.path.basename(output_pkg)}
echo "Extracting tools..."
mkdir -p tools
tar -xzf /tmp/{os.path.basename(tools_pkg)} -C tools/
echo "Setting permissions..."
chmod -R 644 *.html tools/*.html 2>/dev/null
chmod 755 . tools/ tools/ar tools/es tools/zh tools/md 2>/dev/null
echo "Cleaning up /tmp..."
rm -f /tmp/{os.path.basename(output_pkg)} /tmp/{os.path.basename(tools_pkg)}
echo "DONE"
'"""
stdin, stdout, stderr = jd.exec_command(extract_cmd, timeout=60)
output = stdout.read().decode()
err = stderr.read().decode()
print(f" Output: {output}")
if err:
print(f" Stderr: {err[:200]}")
# Step 5: Verify
print("\n[5/5] Verifying deployment...")
verify_cmd = f"""sshpass -p '{RN_PASS}' ssh -o StrictHostKeyChecking=no {RN_USER}@{RN_HOST} '
echo "HTML files in root: $(ls {RN_DIR}*.html 2>/dev/null | wc -l)"
echo "HTML files in tools: $(ls {RN_DIR}tools/*.html 2>/dev/null | wc -l)"
echo "Sitemap size: $(wc -l < {RN_DIR}sitemap.xml 2>/dev/null)"
echo "IndexNow key: $(cat {RN_DIR}72aa77b68704abcfada4020ba81f7c5a.txt 2>/dev/null | head -1)"
echo "BingSiteAuth: $(cat {RN_DIR}BingSiteAuth.xml 2>/dev/null | head -1)"
'"""
stdin, stdout, stderr = jd.exec_command(verify_cmd, timeout=30)
print(stdout.read().decode())
# Clean up JD Cloud temp files
jd.exec_command(f"rm -f {remote_output} {remote_tools}", timeout=10)
jd.close()
print("\nDeployment complete!")
if __name__ == "__main__":
deploy()

61
diagnose_domains.py Normal file
View File

@ -0,0 +1,61 @@
"""Diagnose gfil-lab.com redirect loop and gfil-intel.xyz bot blocking"""
import urllib.request
import http.client
# Test gfil-lab.com
print("=== gfil-lab.com ===")
try:
r = urllib.request.urlopen("https://gfil-lab.com", timeout=15)
print(f"Status: {r.status}")
print(f"URL after redirects: {r.url}")
print(f"Headers: {dict(r.headers)}")
except urllib.error.HTTPError as e:
print(f"HTTPError: {e.code} {e.reason}")
print(f"Headers: {dict(e.headers)}")
print(f"Redirect location: {e.headers.get('Location', 'N/A')}")
except Exception as e:
print(f"Error: {type(e).__name__}: {e}")
# Test with manual redirect following
print("\n=== Manual redirect trace for gfil-lab.com ===")
url = "https://gfil-lab.com"
for i in range(10):
try:
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
r = urllib.request.urlopen(req, timeout=10)
print(f"Hop {i}: {url} -> {r.url} (status {r.status})")
break
except urllib.error.HTTPError as e:
loc = e.headers.get("Location", "")
print(f"Hop {i}: {url} -> {e.code} {e.reason}, Location: {loc}")
if loc:
url = loc
else:
break
except Exception as e:
print(f"Hop {i}: {url} -> Error: {e}")
break
# Test gfil-intel.xyz
print("\n=== gfil-intel.xyz ===")
try:
req = urllib.request.Request("https://gfil-intel.xyz", headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"})
r = urllib.request.urlopen(req, timeout=15)
print(f"Status: {r.status}")
print(f"Size: {len(r.read())} bytes")
except urllib.error.HTTPError as e:
print(f"HTTPError: {e.code} {e.reason}")
body = e.read().decode()[:500]
print(f"Body: {body}")
except Exception as e:
print(f"Error: {type(e).__name__}: {e}")
# Check DNS
print("\n=== DNS Check ===")
import socket
for domain in ["gfil-lab.com", "gfil-intel.xyz"]:
try:
ips = socket.getaddrinfo(domain, 443, socket.AF_INET)
print(f"{domain}: {[x[4][0] for x in ips[:3]]}")
except Exception as e:
print(f"{domain}: DNS error - {e}")

97
diagnose_gfillab.py Normal file
View File

@ -0,0 +1,97 @@
"""Diagnose exactly what's blocking gfil-lab.com"""
import urllib.request, sys, io
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8")
# Test gfil-lab.com with various approaches
print("=== gfil-lab.com 诊断 ===\n")
# 1. Plain request (no UA)
print("[1] 无 User-Agent:")
try:
r = urllib.request.urlopen("https://gfil-lab.com/", timeout=10)
print(f" Status: {r.status}, URL: {r.url}")
except urllib.error.HTTPError as e:
print(f" HTTP {e.code} {e.reason}")
print(f" Server: {e.headers.get('Server','?')}")
print(f" CF-Ray: {e.headers.get('CF-Ray','?')}")
body = e.read().decode()[:300]
print(f" Body: {body}")
# 2. With browser UA
print("\n[2] 浏览器 User-Agent:")
try:
req = urllib.request.Request("https://gfil-lab.com/", headers={
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36"
})
r = urllib.request.urlopen(req, timeout=10)
print(f" Status: {r.status}, URL: {r.url}")
print(f" Size: {len(r.read())} bytes")
except urllib.error.HTTPError as e:
print(f" HTTP {e.code} {e.reason}")
body = e.read().decode()[:300]
print(f" Body: {body}")
# 3. Googlebot UA
print("\n[3] Googlebot User-Agent:")
try:
req = urllib.request.Request("https://gfil-lab.com/", headers={
"User-Agent": "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
})
r = urllib.request.urlopen(req, timeout=10)
print(f" Status: {r.status}, URL: {r.url}")
except urllib.error.HTTPError as e:
print(f" HTTP {e.code} {e.reason}")
body = e.read().decode()[:300]
print(f" Body: {body}")
# 4. Bingbot UA
print("\n[4] Bingbot User-Agent:")
try:
req = urllib.request.Request("https://gfil-lab.com/", headers={
"User-Agent": "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)"
})
r = urllib.request.urlopen(req, timeout=10)
print(f" Status: {r.status}, URL: {r.url}")
except urllib.error.HTTPError as e:
print(f" HTTP {e.code} {e.reason}")
body = e.read().decode()[:300]
print(f" Body: {body}")
# 5. robots.txt
print("\n[5] robots.txt:")
try:
req = urllib.request.Request("https://gfil-lab.com/robots.txt", headers={
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
})
r = urllib.request.urlopen(req, timeout=10)
content = r.read().decode()
print(f" Status: {r.status}")
print(f" Content: {content[:500]}")
except urllib.error.HTTPError as e:
print(f" HTTP {e.code} {e.reason}")
body = e.read().decode()[:300]
print(f" Body: {body}")
# 6. Check CF headers for challenge type
print("\n[6] 检查响应头详情:")
try:
req = urllib.request.Request("https://gfil-lab.com/", headers={
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
})
r = urllib.request.urlopen(req, timeout=10)
for h in ['Server', 'CF-Ray', 'CF-Cache-Status', 'X-Content-Type-Options', 'Content-Type']:
print(f" {h}: {r.headers.get(h, 'N/A')}")
except urllib.error.HTTPError as e:
print(f" HTTP {e.code}")
for h in ['Server', 'CF-Ray', 'CF-Cache-Status', 'Content-Type']:
print(f" {h}: {e.headers.get(h, 'N/A')}")
# 7. HTTP (non-HTTPS) test
print("\n[7] HTTP (非HTTPS):")
try:
r = urllib.request.urlopen("http://gfil-lab.com/", timeout=10)
print(f" Status: {r.status}, URL: {r.url}")
except urllib.error.HTTPError as e:
print(f" HTTP {e.code} {e.reason}")
except Exception as e:
print(f" Error: {type(e).__name__}: {e}")

89
final_audit.py Normal file
View File

@ -0,0 +1,89 @@
"""Final audit: verify all reviewer fixes are live"""
import urllib.request
import re, sys, io
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8")
SITE = "https://blog.quant-view.xyz"
def fetch(path):
try:
url = f"{SITE}/{path}"
r = urllib.request.urlopen(url, timeout=15)
return r.read().decode()
except Exception as e:
return f"ERROR: {e}"
results = []
# 1. entity.html - zero github links, zero liudecai-one
html = fetch("tools/entity.html")
gh = len(re.findall(r'github\.com', html))
l1 = html.count('liudecai-one')
results.append(("entity.html: GitHub links = 0", gh == 0))
results.append(("entity.html: liudecai-one = 0", l1 == 0))
# 2. GitHub SEO article
html = fetch("github-seo-trading-tools.html")
has_npm = 'npmjs.com' in html
has_gitlab = 'gitlab.com/liudecai110' in html
has_degithub = 'de-GitHub' in html
# PyPI should appear in After block exactly once (not duplicated)
after_block = re.search(r'// After:.*?]', html, re.DOTALL)
if after_block:
after_text = after_block.group()
pypi_in_after = after_text.count('https://pypi.org/project/gfil-calculators/')
npm_in_after = 'npmjs.com' in after_text
gitlab_in_after = 'gitlab.com' in after_text
else:
pypi_in_after = -1
npm_in_after = False
gitlab_in_after = False
results.append(("article19: After block PyPI count = 1", pypi_in_after == 1))
results.append(("article19: After block has npm", npm_in_after))
results.append(("article19: After block has GitLab", gitlab_in_after))
results.append(("article19: Mistake#1 updated (de-GitHub)", has_degithub))
results.append(("article19: overall has npm link", has_npm))
results.append(("article19: overall has GitLab link", has_gitlab))
# 3. Footer - English pages use Telegram, not WeChat
html_en = fetch("")
html_zh = fetch("zh/")
en_no_wechat = 'LDP161109' not in html_en
en_has_telegram = '@GFIL_Trading' in html_en or 'Telegram' in html_en
zh_has_wechat = 'LDP161109' in html_zh
results.append(("EN index: NO WeChat/QQ", en_no_wechat))
results.append(("EN index: HAS Telegram", en_has_telegram))
results.append(("ZH index: HAS WeChat/QQ", zh_has_wechat))
# 4. research.html - "GitHub" label fixed to "PyPI"
html = fetch("tools/research.html")
# Check that PyPI link text is NOT "GitHub"
pypi_with_github_label = bool(re.search(r'pypi\.org[^>]*>GitHub</a>', html))
results.append(("research.html: no mislabeled GitHub->PyPI", not pypi_with_github_label))
# 5. gfil-faq.html - has GitLab, no "GitHub" label on PyPI
html = fetch("tools/gfil-faq.html")
has_gitlab_faq = 'gitlab.com/liudecai110' in html
results.append(("gfil-faq.html: has GitLab link", has_gitlab_faq))
# 6. media.html - zero github links
html = fetch("tools/media.html")
gh = len(re.findall(r'github\.com', html))
results.append(("media.html: GitHub links = 0", gh == 0))
# Print results
print("=" * 70)
print("FINAL AUDIT: Reviewer Fixes Verification")
print("=" * 70)
all_pass = True
for label, passed in results:
status = "PASS" if passed else "FAIL"
if not passed:
all_pass = False
print(f" [{status}] {label}")
print()
if all_pass:
print("ALL CHECKS PASSED")
else:
print("SOME CHECKS FAILED")

25
final_check.py Normal file
View File

@ -0,0 +1,25 @@
import urllib.request, sys, io
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8")
for domain in ["gfil-lab.com", "gfil-intel.xyz", "blog.quant-view.xyz"]:
try:
url = "https://" + domain + "/robots.txt?nocache=1"
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
r = urllib.request.urlopen(req, timeout=10)
content = r.read().decode()
gb = "GPTBot" in content
cb = "ClaudeBot" in content
pb = "PerplexityBot" in content
sm = "Sitemap" in content
print(domain + ": " + str(r.status) + " | " + str(len(content)) + " chars | GPTBot=" + str(gb) + " ClaudeBot=" + str(cb) + " PerplexityBot=" + str(pb) + " Sitemap=" + str(sm))
except Exception as e:
print(domain + ": " + str(e))
# Also check homepage still works
for domain in ["gfil-lab.com", "gfil-intel.xyz"]:
try:
req = urllib.request.Request("https://" + domain + "/", headers={"User-Agent": "Mozilla/5.0"})
r = urllib.request.urlopen(req, timeout=10)
print(domain + " homepage: " + str(r.status) + " OK")
except Exception as e:
print(domain + " homepage: ERROR " + str(e))

125
fix_and_verify.py Normal file
View File

@ -0,0 +1,125 @@
import paramiko, sys, io, time
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8")
JD_HOST = "111.228.37.165"
JD_USER = "root"
JD_PASS = "Liudecai110"
LAB_HOST = "216.144.233.14"
LAB_USER = "root"
LAB_PASS = "Kt9V72Tx2c48ChikKU"
# Fix script that modifies BOTH server blocks
FIX_SCRIPT = r'''
import shutil
# Fix the "default" config (server_name: gfil-lab.com - this is the one that actually serves gfil-lab.com)
src = "/etc/nginx/sites-enabled/default"
bak = "/etc/nginx/sites-enabled/default.bak.before-robots"
shutil.copy2(src, bak)
with open(src, "r") as f:
content = f.read()
robots_block = " location = /robots.txt {\n alias /var/www/gfil-lab/robots.txt;\n default_type text/plain;\n }\n\n"
if "robots.txt" not in content:
content = content.replace(" location / {", robots_block + " location / {")
with open(src, "w") as f:
f.write(content)
print("INSERTED into default")
else:
print("ALREADY in default")
'''
script_path = r"C:\Users\thinkpad\AppData\Local\Temp\kilo\fix_default.py"
with open(script_path, "w") as f:
f.write(FIX_SCRIPT)
jd = paramiko.SSHClient()
jd.set_missing_host_key_policy(paramiko.AutoAddPolicy())
jd.connect(JD_HOST, port=22, username=JD_USER, password=JD_PASS,
timeout=20, banner_timeout=60, allow_agent=False, look_for_keys=False)
sftp = jd.open_sftp()
sftp.put(script_path, "/tmp/fix_default.py")
sftp.close()
# SCP and run
scp_cmd = "sshpass -p '" + LAB_PASS + "' scp -o StrictHostKeyChecking=no /tmp/fix_default.py " + LAB_USER + "@" + LAB_HOST + ":/tmp/fix_default.py"
stdin, stdout, stderr = jd.exec_command(scp_cmd, timeout=15)
stdout.channel.recv_exit_status()
run_cmd = "sshpass -p '" + LAB_PASS + "' ssh -o StrictHostKeyChecking=no " + LAB_USER + "@" + LAB_HOST + " 'python3 /tmp/fix_default.py && echo --- && cat /etc/nginx/sites-enabled/default && echo --- && nginx -t 2>&1 && (systemctl reload nginx && echo NGINX_OK) || (cp /etc/nginx/sites-enabled/default.bak.before-robots /etc/nginx/sites-enabled/default && nginx -t && systemctl reload nginx && echo ROLLBACK_OK) && rm -f /tmp/fix_default.py'"
stdin, stdout, stderr = jd.exec_command(run_cmd, timeout=30)
print(stdout.read().decode())
jd.close()
time.sleep(2)
# === STEP 2: Code verification ===
print("\n=== STEP 2: CODE VERIFICATION ===")
# 2a. External check
import urllib.request
all_pass = True
for domain in ["gfil-lab.com", "gfil-intel.xyz"]:
# Homepage
try:
req = urllib.request.Request("https://" + domain + "/", headers={"User-Agent": "Mozilla/5.0"})
r = urllib.request.urlopen(req, timeout=10)
print(f" {domain} homepage: {r.status} OK")
except Exception as e:
print(f" {domain} homepage: ERROR {e}")
all_pass = False
# robots.txt
try:
req = urllib.request.Request("https://" + domain + "/robots.txt", headers={"User-Agent": "Mozilla/5.0"})
r = urllib.request.urlopen(req, timeout=10)
content = r.read().decode()
checks = {
"GPTBot": "GPTBot" in content,
"ClaudeBot": "ClaudeBot" in content,
"PerplexityBot": "PerplexityBot" in content,
"Sitemap": "Sitemap:" in content,
"Size>500": len(content) > 500,
}
status = "PASS" if all(checks.values()) else "FAIL"
if not all(checks.values()):
all_pass = False
print(f" {domain} robots.txt: [{status}] {dict(checks)}")
except Exception as e:
print(f" {domain} robots.txt: ERROR {e}")
all_pass = False
# Googlebot
try:
req = urllib.request.Request("https://gfil-lab.com/robots.txt", headers={"User-Agent": "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"})
r = urllib.request.urlopen(req, timeout=10)
content = r.read().decode()
print(f" Googlebot -> gfil-lab.com/robots.txt: {r.status}, GPTBot={'GPTBot' in content}")
except Exception as e:
print(f" Googlebot check: ERROR {e}")
all_pass = False
print()
if all_pass:
print("ALL CODE CHECKS PASSED")
else:
print("SOME CHECKS FAILED")
# === STEP 3: Human checklist ===
print("\n" + "=" * 60)
print("STEP 3: HUMAN OBSERVATION CHECKLIST")
print("=" * 60)
print()
print("Please manually verify:")
print(" 1. https://gfil-lab.com/ -> loads normally")
print(" 2. https://gfil-lab.com/robots.txt -> shows FULL version with GPTBot/ClaudeBot/PerplexityBot")
print(" 3. https://gfil-intel.xyz/robots.txt -> shows robots.txt")
print(" 4. https://gfil-lab.com/login -> login page works")
print()
print("Rollback if needed:")
print(" ssh root@216.144.233.14")
print(" cp /etc/nginx/sites-enabled/default.bak.before-robots /etc/nginx/sites-enabled/default")
print(" cp /etc/nginx/sites-enabled/gfil.bak.before-robots /etc/nginx/sites-enabled/gfil")
print(" systemctl reload nginx")

43
fix_sites_enabled.py Normal file
View File

@ -0,0 +1,43 @@
"""Remove broken backup file from sites-enabled, keep only clean gfil"""
import paramiko
JD_HOST = "111.228.37.165"
JD_USER = "root"
JD_PASS = "Liudecai110"
LAB_HOST = "216.144.233.14"
LAB_USER = "root"
LAB_PASS = "Kt9V72Tx2c48ChikKU"
jd = paramiko.SSHClient()
jd.set_missing_host_key_policy(paramiko.AutoAddPolicy())
jd.connect(JD_HOST, port=22, username=JD_USER, password=JD_PASS,
timeout=20, banner_timeout=60, allow_agent=False, look_for_keys=False)
cmd = f"""sshpass -p '{LAB_PASS}' ssh -o StrictHostKeyChecking=no {LAB_USER}@{LAB_HOST} '
# Remove the broken backup from sites-enabled (nginx loads ALL files in this dir)
rm -f /etc/nginx/sites-enabled/gfil.bak.broken
# Verify only clean files remain
echo "=== sites-enabled contents ==="
ls -la /etc/nginx/sites-enabled/
# Show current gfil config
echo "=== Current gfil config ==="
cat /etc/nginx/sites-enabled/gfil
# Test
nginx -t 2>&1
if [ $? -eq 0 ]; then
systemctl reload nginx
echo "SUCCESS: Nginx restored and reloaded"
else
echo "FAILED"
fi
# Final check - site responding
curl -s -o /dev/null -w "HTTP status" http://localhost/ 2>/dev/null
'"""
stdin, stdout, stderr = jd.exec_command(cmd, timeout=30)
print(stdout.read().decode())
jd.close()

36
npm_package/README.md Normal file
View File

@ -0,0 +1,36 @@
# Trading Calculators
Free trading calculators for forex, gold, and crypto traders.
## Installation
```bash
npm install @liudecai-one/trading-calculators-free
```
## Usage
```js
const { positionSize, pipValue, fibonacci } = require('@liudecai-one/trading-calculators-free');
// Position size: account=$10K, risk=1%, stop=20 pips
const size = positionSize(10000, 1, 20);
console.log({ size }); // 0.5 lots
// Fibonacci retracement levels
const fib = fibonacci(1.1200, 1.1000);
console.log({ fib });
```
## Free Web Tools
- [Position Size Calculator](https://blog.quant-view.xyz/tools/position-size-calculator.html)
- [Pip Value Calculator](https://blog.quant-view.xyz/tools/pip-calculator.html)
- [Margin Calculator](https://blog.quant-view.xyz/tools/margin-calculator.html)
- [Fibonacci Calculator](https://blog.quant-view.xyz/tools/fibonacci-calculator.html)
- [ATR Calculator](https://blog.quant-view.xyz/tools/atr-calculator.html)
- [Risk-Reward Calculator](https://blog.quant-view.xyz/tools/risk-reward-calculator.html)
- [Drawdown Calculator](https://blog.quant-view.xyz/tools/drawdown-calculator.html)
## More Resources
- [Trading Blog](https://blog.quant-view.xyz)
- [GFIL Terminal](http://gfil-intel.xyz/)
- [Telegram Community](https://t.me/GFIL_Trading)
- [Discord Server](https://discord.gg/GMmMCD4MCr)

29
npm_package/index.js Normal file
View File

@ -0,0 +1,29 @@
/**
* Free Trading Calculators
* Web versions: https://blog.quant-view.xyz/tools/
* Telegram: https://t.me/GFIL_Trading
* Discord: https://discord.gg/GMmMCD4MCr
*/
function positionSize(accountBalance, riskPercent, stopLossPips, pipValue = 10) {
const riskAmount = accountBalance * (riskPercent / 100);
return parseFloat((riskAmount / (stopLossPips * pipValue)).toFixed(2));
}
function pipValue(currencyPair, lotSize = 1) {
const rates = { "EURUSD": 10, "GBPUSD": 10, "USDJPY": 9.3, "XAUUSD": 10 };
return rates[currencyPair] * lotSize || 10;
}
function fibonacci(high, low) {
const diff = high - low;
return {
"0.236": high - diff * 0.236,
"0.382": high - diff * 0.382,
"0.500": high - diff * 0.500,
"0.618": high - diff * 0.618,
"0.786": high - diff * 0.786,
};
}
module.exports = { positionSize, pipValue, fibonacci };

22
npm_package/package.json Normal file
View File

@ -0,0 +1,22 @@
{
"name": "@liudecai-one/trading-calculators-free",
"version": "1.0.0",
"description": "Free trading calculators: position size, pip value, margin, Fibonacci, ATR. Web versions at blog.quant-view.xyz/tools/",
"main": "index.js",
"keywords": [
"trading",
"forex",
"calculator",
"position-size",
"pip-calculator",
"margin-calculator",
"fibonacci",
"atr"
],
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://gitlab.com/liudecai110/gfil-trading-calculators.git"
},
"homepage": "https://blog.quant-view.xyz/tools/"
}

57
probe_nginx.py Normal file
View File

@ -0,0 +1,57 @@
"""Deep probe: find Nginx configs and deploy robots.txt correctly"""
import paramiko
import time
JD_HOST = "111.228.37.165"
JD_USER = "root"
JD_PASS = "Liudecai110"
LAB_HOST = "216.144.233.14"
LAB_USER = "root"
LAB_PASS = "Kt9V72Tx2c48ChikKU"
RN_HOST = "107.174.186.162"
RN_USER = "root"
RN_PASS = "liudapao2026"
jd = paramiko.SSHClient()
jd.set_missing_host_key_policy(paramiko.AutoAddPolicy())
jd.connect(JD_HOST, port=22, username=JD_USER, password=JD_PASS,
timeout=20, banner_timeout=60, allow_agent=False, look_for_keys=False)
# === gfil-lab.com (216.144.233.14) ===
print("=== gfil-lab.com (216.144.233.14) ===")
cmd = f"""sshpass -p '{LAB_PASS}' ssh -o StrictHostKeyChecking=no {LAB_USER}@{LAB_HOST} '
echo "--- All Nginx configs ---"
ls -la /etc/nginx/sites-enabled/ 2>/dev/null
ls -la /etc/nginx/conf.d/ 2>/dev/null
echo "--- Full Nginx config ---"
cat /etc/nginx/sites-enabled/default 2>/dev/null | head -50
cat /etc/nginx/conf.d/default.conf 2>/dev/null | head -50
echo "--- Find gfil-lab server block ---"
grep -rl "gfil-lab\\|server_name" /etc/nginx/ 2>/dev/null
echo "--- Nginx test ---"
nginx -T 2>/dev/null | grep -A3 "server_name" | head -30
'"""
stdin, stdout, stderr = jd.exec_command(cmd, timeout=30)
print(stdout.read().decode()[:3000])
# === gfil-intel.xyz (RackNerd) ===
print("\n=== gfil-intel.xyz (RackNerd) ===")
cmd2 = f"""sshpass -p '{RN_PASS}' ssh -o StrictHostKeyChecking=no {RN_USER}@{RN_HOST} '
echo "--- gfil-intel Nginx config ---"
cat /etc/nginx/sites-available/gfil-mask 2>/dev/null | head -60
echo "--- Sites enabled ---"
ls -la /etc/nginx/sites-enabled/ 2>/dev/null
echo "--- Check if gfil-mask is enabled ---"
ls -la /etc/nginx/sites-enabled/gfil-mask 2>/dev/null
'"""
stdin, stdout, stderr = jd.exec_command(cmd2, timeout=30)
print(stdout.read().decode()[:3000])
jd.close()

58
purge_and_verify.py Normal file
View File

@ -0,0 +1,58 @@
import urllib.request, json, sys, io, time
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8")
# Purge gfil-intel.xyz zone
CF_TOKEN = "cfut_xRDcVVOTE9hLWxe8fFUG1Xgv7aQVtV0ytWFYZKimffcc10e3"
ZONE_ID = "a107f45f3d82e7209447cec396504d0b"
headers = {
"Authorization": "Bearer " + CF_TOKEN,
"Content-Type": "application/json"
}
purge_data = json.dumps({"files": ["https://gfil-intel.xyz/robots.txt"]}).encode("utf-8")
req = urllib.request.Request(
f"https://api.cloudflare.com/client/v4/zones/{ZONE_ID}/purge_cache",
data=purge_data,
headers=headers,
method="POST"
)
r = urllib.request.urlopen(req, timeout=15)
result = json.loads(r.read().decode())
print("gfil-intel.xyz purge:", result.get("success", False))
# Also purge blog.quant-view.xyz
ZONE_ID_BLOG = "3712ed1fcbd198c3ec6bd9758563a8d5"
purge_data2 = json.dumps({"files": ["https://blog.quant-view.xyz/robots.txt"]}).encode("utf-8")
req2 = urllib.request.Request(
f"https://api.cloudflare.com/client/v4/zones/{ZONE_ID_BLOG}/purge_cache",
data=purge_data2,
headers=headers,
method="POST"
)
r2 = urllib.request.urlopen(req2, timeout=15)
result2 = json.loads(r2.read().decode())
print("blog.quant-view.xyz purge:", result2.get("success", False))
# Wait
print("\nWaiting 5 seconds...")
time.sleep(5)
# Verify all 3 domains
print("\n=== VERIFICATION ===")
for domain in ["gfil-lab.com", "gfil-intel.xyz", "blog.quant-view.xyz"]:
try:
req = urllib.request.Request("https://" + domain + "/robots.txt",
headers={"User-Agent": "Mozilla/5.0", "Cache-Control": "no-cache", "Pragma": "no-cache"})
r = urllib.request.urlopen(req, timeout=10)
content = r.read().decode()
checks = {
"GPTBot": "GPTBot" in content,
"ClaudeBot": "ClaudeBot" in content,
"PerplexityBot": "PerplexityBot" in content,
"SizeOK": len(content) > 100
}
status = "PASS" if all(checks.values()) else "FAIL"
print(f" [{status}] {domain}: {len(content)} chars | {checks}")
except Exception as e:
print(f" [FAIL] {domain}: {e}")

85
purge_cf_cache.py Normal file
View File

@ -0,0 +1,85 @@
"""Purge Cloudflare cache for robots.txt on gfil-lab.com"""
import urllib.request, json, sys, io
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8")
# gfil-lab.com Cloudflare zone
CF_TOKEN = "cfut_xRDcVVOTE9hLWxe8fFUG1Xgv7aQVtV0ytWFYZKimffcc10e3"
# Need zone ID for gfil-lab.com - get it first
headers = {
"Authorization": "Bearer " + CF_TOKEN,
"Content-Type": "application/json"
}
# List zones to find gfil-lab.com zone ID
req = urllib.request.Request("https://api.cloudflare.com/client/v4/zones", headers=headers)
r = urllib.request.urlopen(req, timeout=15)
data = json.loads(r.read().decode())
for z in data.get("result", []):
print(f" Zone: {z['name']} -> ID: {z['id']}")
# Find gfil-lab.com zone
zone_id = None
for z in data.get("result", []):
if z["name"] == "gfil-lab.com":
zone_id = z["id"]
break
if not zone_id:
print("ERROR: gfil-lab.com zone not found")
sys.exit(1)
print(f"\nPurging cache for gfil-lab.com (zone: {zone_id})...")
# Purge specific URLs
purge_data = json.dumps({
"files": [
"https://gfil-lab.com/robots.txt",
"https://gfil-intel.xyz/robots.txt"
]
}).encode("utf-8")
req = urllib.request.Request(
f"https://api.cloudflare.com/client/v4/zones/{zone_id}/purge_cache",
data=purge_data,
headers=headers,
method="POST"
)
r = urllib.request.urlopen(req, timeout=15)
result = json.loads(r.read().decode())
print(f" Purge result: {result.get('success', False)}")
# Also try gfil-intel.xyz zone
zone_id2 = None
for z in data.get("result", []):
if z["name"] == "gfil-intel.xyz":
zone_id2 = z["id"]
break
if zone_id2:
print(f"\nPurging cache for gfil-intel.xyz (zone: {zone_id2})...")
purge_data2 = json.dumps({"files": ["https://gfil-intel.xyz/robots.txt"]}).encode("utf-8")
req2 = urllib.request.Request(
f"https://api.cloudflare.com/client/v4/zones/{zone_id2}/purge_cache",
data=purge_data2,
headers=headers,
method="POST"
)
r2 = urllib.request.urlopen(req2, timeout=15)
result2 = json.loads(r2.read().decode())
print(f" Purge result: {result2.get('success', False)}")
# Wait and verify
import time
print("\nWaiting 3 seconds for cache purge...")
time.sleep(3)
print("\n=== Verification after purge ===")
import urllib.request as ur
for domain in ["gfil-lab.com", "gfil-intel.xyz"]:
try:
req = ur.Request("https://" + domain + "/robots.txt", headers={"User-Agent": "Mozilla/5.0", "Cache-Control": "no-cache"})
r = ur.urlopen(req, timeout=10)
content = r.read().decode()
print(f" {domain}: {r.status} | {len(content)} chars | GPTBot={'GPTBot' in content} | ClaudeBot={'ClaudeBot' in content}")
except Exception as e:
print(f" {domain}: {e}")

1
requirements.txt Normal file
View File

@ -0,0 +1 @@
paramiko>=3.0

40
restore_nginx.py Normal file
View File

@ -0,0 +1,40 @@
"""RESTORE: Copy clean config from sites-available/gfil"""
import paramiko
JD_HOST = "111.228.37.165"
JD_USER = "root"
JD_PASS = "Liudecai110"
LAB_HOST = "216.144.233.14"
LAB_USER = "root"
LAB_PASS = "Kt9V72Tx2c48ChikKU"
jd = paramiko.SSHClient()
jd.set_missing_host_key_policy(paramiko.AutoAddPolicy())
jd.connect(JD_HOST, port=22, username=JD_USER, password=JD_PASS,
timeout=20, banner_timeout=60, allow_agent=False, look_for_keys=False)
# Check sites-available/gfil content first, then copy it over
restore_cmd = f"""sshpass -p '{LAB_PASS}' ssh -o StrictHostKeyChecking=no {LAB_USER}@{LAB_HOST} '
# Show the clean original
echo "=== sites-available/gfil (original clean) ==="
cat /etc/nginx/sites-available/gfil
# Copy clean version over the broken one
cp /etc/nginx/sites-available/gfil /etc/nginx/sites-enabled/gfil
# Test
nginx -t 2>&1
if [ $? -eq 0 ]; then
systemctl reload nginx
echo "RESTORED: Nginx reloaded with clean config"
else
echo "STILL FAILING after restore"
fi
# Verify site is back
curl -s -o /dev/null -w "%{{http_code}}" http://localhost/ 2>/dev/null
'"""
stdin, stdout, stderr = jd.exec_command(restore_cmd, timeout=30)
print(stdout.read().decode())
jd.close()

42
revert_nginx.py Normal file
View File

@ -0,0 +1,42 @@
"""REVERT: Remove broken robots.txt block from gfil-lab.com Nginx config"""
import paramiko
JD_HOST = "111.228.37.165"
JD_USER = "root"
JD_PASS = "Liudecai110"
LAB_HOST = "216.144.233.14"
LAB_USER = "root"
LAB_PASS = "Kt9V72Tx2c48ChikKU"
jd = paramiko.SSHClient()
jd.set_missing_host_key_policy(paramiko.AutoAddPolicy())
jd.connect(JD_HOST, port=22, username=JD_USER, password=JD_PASS,
timeout=20, banner_timeout=60, allow_agent=False, look_for_keys=False)
# Remove ALL robots.txt related lines from the Nginx config
revert_cmd = """sshpass -p 'Kt9V72Tx2c48ChikKU' ssh -o StrictHostKeyChecking=no root@216.144.233.14 '
# Remove the broken "n" line
sed -i "/^n location/d" /etc/nginx/sites-enabled/gfil
# Remove the robots.txt location block (3 lines: open, alias, close)
sed -i "/location = \/robots\.txt/,/}/d" /etc/nginx/sites-enabled/gfil
# Remove any leftover empty lines
sed -i "/^$/N;/^\\n$/d" /etc/nginx/sites-enabled/gfil
# Verify config is clean
echo "=== Cleaned config ==="
cat /etc/nginx/sites-enabled/gfil
# Test
nginx -t 2>&1
if [ $? -eq 0 ]; then
systemctl reload nginx
echo "Nginx reloaded OK - config reverted"
else
echo "STILL FAILING - showing full config"
cat -n /etc/nginx/sites-enabled/gfil
fi
'"""
stdin, stdout, stderr = jd.exec_command(revert_cmd, timeout=30)
print(stdout.read().decode())
jd.close()

38
revert_v2.py Normal file
View File

@ -0,0 +1,38 @@
"""REVERT v2: Remove leftover lines 13-15 from gfil Nginx config"""
import paramiko
JD_HOST = "111.228.37.165"
JD_USER = "root"
JD_PASS = "Liudecai110"
LAB_HOST = "216.144.233.14"
LAB_USER = "root"
LAB_PASS = "Kt9V72Tx2c48ChikKU"
jd = paramiko.SSHClient()
jd.set_missing_host_key_policy(paramiko.AutoAddPolicy())
jd.connect(JD_HOST, port=22, username=JD_USER, password=JD_PASS,
timeout=20, banner_timeout=60, allow_agent=False, look_for_keys=False)
# Precisely remove the 3 leftover lines
revert_cmd = r"""sshpass -p 'Kt9V72Tx2c48ChikKU' ssh -o StrictHostKeyChecking=no root@216.144.233.14 '
# Remove the 3 leftover lines from robots.txt block
sed -i "/alias \/var\/www\/gfil-lab\/robots\.txt/d" /etc/nginx/sites-enabled/gfil
sed -i "/default_type text\/plain/d" /etc/nginx/sites-enabled/gfil
# Remove the orphan closing brace on its own line after the comment line
sed -i "/^ }$/d" /etc/nginx/sites-enabled/gfil
echo "=== Final config ==="
cat -n /etc/nginx/sites-enabled/gfil
nginx -t 2>&1
if [ $? -eq 0 ]; then
systemctl reload nginx
echo "SUCCESS: Nginx reloaded, config clean"
else
echo "STILL FAILING"
fi
'"""
stdin, stdout, stderr = jd.exec_command(revert_cmd, timeout=30)
print(stdout.read().decode())
jd.close()

112
submit_indexnow.py Normal file
View File

@ -0,0 +1,112 @@
"""Submit new blog URLs to IndexNow (Bing, Yandex, Seznam)"""
import urllib.request
import json
import os
import sys
SITE = "https://blog.quant-view.xyz"
KEY = "72aa77b68704abcfada4020ba81f7c5a"
# New pages from the 54 variant generator
new_pages = [
# Formula pages (10)
"tools/position-size-formula.html",
"tools/pip-value-formula.html",
"tools/kelly-criterion-formula.html",
"tools/atr-formula.html",
"tools/fibonacci-retracement-formula.html",
"tools/drawdown-formula.html",
"tools/margin-formula.html",
"tools/risk-reward-formula.html",
"tools/compound-interest-formula.html",
"tools/profit-factor-formula.html",
# Gold pages (6)
"tools/gold-atr-calculator.html",
"tools/gold-margin-calculator.html",
"tools/gold-drawdown-calculator.html",
"tools/xauusd-trading-guide.html",
"tools/gold-lot-size-calculator.html",
"tools/gold-spread-calculator.html",
# Forex pages (5)
"tools/forex-position-size-calculator.html",
"tools/forex-pip-calculator.html",
"tools/forex-margin-calculator.html",
"tools/forex-risk-calculator.html",
"tools/forex-lot-size-calculator.html",
# Forex pair guides (3)
"tools/eurusd-trading-guide.html",
"tools/gbpusd-trading-guide.html",
"tools/usdjpy-trading-guide.html",
# Crypto pages (5)
"tools/btc-position-size-calculator.html",
"tools/crypto-pip-calculator.html",
"tools/btc-margin-calculator.html",
"tools/eth-position-size-calculator.html",
"tools/crypto-risk-calculator.html",
# Pip variants (9)
"tools/pip-calculator-eurgbp.html",
"tools/pip-calculator-usdchf.html",
"tools/pip-calculator-solusd.html",
"tools/pip-calculator-dogeusd.html",
"tools/pip-calculator-adausd.html",
"tools/pip-calculator-bnbusd.html",
"tools/pip-calculator-dax40.html",
"tools/pip-calculator-sp500.html",
"tools/pip-calculator-ukoil.html",
# Index pages (4)
"tools/sp500-position-size-calculator.html",
"tools/nas100-position-size-calculator.html",
"tools/dax40-position-size-calculator.html",
"tools/index-margin-calculator.html",
# Educational (6)
"tools/risk-management-guide.html",
"tools/how-to-calculate-pip-value.html",
"tools/how-to-use-atr-for-stop-loss.html",
"tools/kelly-criterion-explained.html",
"tools/drawdown-recovery-guide.html",
"tools/margin-call-prevention.html",
# Comparison (3)
"tools/tradingview-vs-mt5.html",
"tools/ctrader-vs-mt5.html",
"tools/best-free-trading-tools.html",
# Account size variants (3)
"tools/position-size-calculator-100000-dollar-account.html",
"tools/position-size-calculator-20000-dollar-account.html",
"tools/position-size-calculator-3000-dollar-account.html",
# New articles
"position-size-calculator-guide.html",
"gold-trading-2026-guide.html",
"ssh-tunnel-deployment-china.html",
"github-seo-trading-tools.html",
"gold-pip-value-calculator-wrong.html",
# Sitemap
"sitemap.xml",
]
urls = [f"{SITE}/{p}" for p in new_pages]
print(f"Submitting {len(urls)} URLs to IndexNow...")
payload = json.dumps({
"host": "blog.quant-view.xyz",
"key": KEY,
"keyLocation": f"{SITE}/{KEY}.txt",
"urlList": urls
}).encode("utf-8")
engines = [
("Bing", "https://www.bing.com/indexnow"),
("Yandex", "https://yandex.com/indexnow"),
("Seznam", "https://search.seznam.cz/indexnow"),
]
for name, endpoint in engines:
try:
req = urllib.request.Request(endpoint, data=payload, headers={"Content-Type": "application/json"})
resp = urllib.request.urlopen(req, timeout=30)
print(f" {name}: HTTP {resp.status}")
except urllib.error.HTTPError as e:
print(f" {name}: HTTP {e.code} ({e.reason})")
except Exception as e:
print(f" {name}: Error - {e}")
print("Done!")

46
verify_nginx.py Normal file
View File

@ -0,0 +1,46 @@
"""Verify Nginx config: compare sites-enabled/gfil vs sites-available/gfil"""
import paramiko
JD_HOST = "111.228.37.165"
JD_USER = "root"
JD_PASS = "Liudecai110"
LAB_HOST = "216.144.233.14"
LAB_USER = "root"
LAB_PASS = "Kt9V72Tx2c48ChikKU"
jd = paramiko.SSHClient()
jd.set_missing_host_key_policy(paramiko.AutoAddPolicy())
jd.connect(JD_HOST, port=22, username=JD_USER, password=JD_PASS,
timeout=20, banner_timeout=60, allow_agent=False, look_for_keys=False)
cmd = f"""sshpass -p '{LAB_PASS}' ssh -o StrictHostKeyChecking=no {LAB_USER}@{LAB_HOST} '
echo "=== Diff: sites-enabled vs sites-available ==="
diff /etc/nginx/sites-enabled/gfil /etc/nginx/sites-available/gfil && echo "IDENTICAL" || echo "DIFFERENT"
echo ""
echo "=== sites-available/gfil (original, date) ==="
ls -la /etc/nginx/sites-available/gfil
stat /etc/nginx/sites-available/gfil | grep -i modify
echo ""
echo "=== sites-enabled/gfil (current, date) ==="
ls -la /etc/nginx/sites-enabled/gfil
stat /etc/nginx/sites-enabled/gfil | grep -i modify
echo ""
echo "=== Full current config ==="
cat /etc/nginx/sites-enabled/gfil
echo ""
echo "=== Nginx status ==="
nginx -t 2>&1
systemctl status nginx --no-pager | head -5
echo ""
echo "=== Site response ==="
curl -s -o /dev/null -w "HTTP_code:%{{http_code}} Size:%{{size_download}}" http://localhost/ 2>/dev/null
'"""
stdin, stdout, stderr = jd.exec_command(cmd, timeout=30)
print(stdout.read().decode())
jd.close()