1<!DOCTYPE html> 2<html lang="en"> 3<head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <title>The Black Hole Bay - Documentation</title> 7 <meta name="description" content="A fast, DHT-powered torrent search engine and community platform with a public REST API."> 8 <link rel="icon" type="image/jpeg" href="/images/icon-haloween.jpg"> 9 <style> 10 :root{--bg:#050505;--bg2:#0a0a0a;--card:#0d0d0d;--border:#1a1a1a;--border2:#2a2a2a;--text:#e0e0e0;--text2:#888;--text3:#555;--orange:#ff6b35;--green:#00d27a;--blue:#3b82f6;--purple:#8b7cff;--code-bg:#020202;} 11 *{box-sizing:border-box;margin:0;padding:0;} 12 body{background:var(--bg);color:var(--text);font-family:'Segoe UI',-apple-system,sans-serif;line-height:1.6;background-image:url('https://www.transparenttextures.com/patterns/stardust.png');background-attachment:fixed;} 13 a{color:var(--orange);text-decoration:none;transition:color .15s;} 14 a:hover{text-decoration:underline;} 15 ::selection{background:var(--orange);color:#fff;} 16 ::-webkit-scrollbar{width:8px;height:8px;} 17 ::-webkit-scrollbar-track{background:var(--bg2);} 18 ::-webkit-scrollbar-thumb{background:var(--border2);border-radius:4px;} 19 ::-webkit-scrollbar-thumb:hover{background:var(--text3);} 20 code,pre{font-family:'SF Mono','Fira Code','Courier New',monospace;font-size:13px;} 21 22 /* NAV */ 23 .nav{position:sticky;top:0;z-index:100;background:rgba(5,5,5,.9);backdrop-filter:blur(12px);border-bottom:1px solid var(--border);display:flex;align-items:center;justify-content:space-between;padding:10px 24px;} 24 .nav-brand{display:flex;align-items:center;gap:10px;font-weight:700;font-size:15px;color:var(--text);} 25 .nav-brand img{width:26px;height:26px;border-radius:6px;} 26 .nav-links{display:flex;gap:20px;align-items:center;} 27 .nav-links a{color:var(--text2);font-size:14px;font-weight:600;} 28 .nav-links a:hover{color:var(--orange);text-decoration:none;} 29 30 /* HERO */ 31 .hero{text-align:center;padding:70px 20px 50px;} 32 .hero-logo{width:80px;height:80px;border-radius:18px;border:2px solid #fff;box-shadow:0 0 40px rgba(255,107,53,.15);margin-bottom:20px;} 33 .hero h1{font-size:36px;margin-bottom:12px;letter-spacing:-.5px;} 34 .hero .tagline{color:var(--text2);font-size:17px;max-width:580px;margin:0 auto 24px;} 35 .badges{display:flex;gap:8px;justify-content:center;flex-wrap:wrap;} 36 .badge{background:var(--card);border:1px solid var(--border2);padding:6px 14px;border-radius:6px;font-size:12px;color:var(--text2);font-weight:600;} 37 .badge b{color:var(--text);} 38 .hero-cta{display:flex;gap:12px;justify-content:center;margin-top:28px;flex-wrap:wrap;} 39 .btn{display:inline-flex;align-items:center;gap:6px;padding:10px 20px;border-radius:8px;font-size:14px;font-weight:600;text-decoration:none;transition:all .15s;} 40 .btn-primary{background:var(--orange);color:#fff;} 41 .btn-primary:hover{background:#e55a25;text-decoration:none;} 42 .btn-ghost{background:var(--card);border:1px solid var(--border2);color:var(--text);} 43 .btn-ghost:hover{border-color:var(--orange);text-decoration:none;color:var(--orange);} 44 45 /* SECTIONS */ 46 .section{max-width:860px;margin:0 auto;padding:0 20px;} 47 .section-title{font-size:24px;font-weight:700;margin-bottom:20px;display:flex;align-items:center;gap:8px;} 48 .section-title .bar{width:4px;height:24px;background:var(--orange);border-radius:2px;} 49 50 /* CARDS */ 51 .grid{display:grid;gap:16px;margin-bottom:40px;} 52 .grid-3{grid-template-columns:repeat(3,1fr);} 53 .grid-2{grid-template-columns:repeat(2,1fr);} 54 .fcard{background:var(--card);border:1px solid var(--border);border-radius:12px;padding:20px;transition:border-color .2s,transform .2s;} 55 .fcard:hover{border-color:var(--border2);transform:translateY(-2px);} 56 .fcard-icon{width:36px;height:36px;border-radius:8px;background:rgba(255,107,53,.1);display:flex;align-items:center;justify-content:center;margin-bottom:12px;} 57 .fcard-icon svg{width:20px;height:20px;color:var(--orange);} 58 .fcard h3{font-size:15px;margin-bottom:6px;} 59 .fcard p{font-size:13px;color:var(--text2);line-height:1.5;} 60 61 /* CODE */ 62 .code-block{background:var(--code-bg);border:1px solid var(--border);border-radius:10px;overflow:hidden;margin:12px 0;} 63 .code-head{background:var(--bg2);border-bottom:1px solid var(--border);padding:8px 14px;display:flex;align-items:center;justify-content:space-between;} 64 .code-lang{font-size:12px;color:var(--text3);font-family:monospace;text-transform:uppercase;letter-spacing:.5px;} 65 .copy-btn{background:transparent;border:1px solid var(--border2);color:var(--text2);font-size:12px;padding:3px 10px;border-radius:5px;cursor:pointer;transition:all .15s;} 66 .copy-btn:hover{background:var(--card);color:var(--orange);border-color:var(--orange);} 67 .copy-btn.copied{color:var(--green);border-color:var(--green);} 68 .code-body{padding:14px;overflow-x:auto;} 69 .code-body code{color:#c8c8c8;} 70 71 /* TABLE */ 72 .tbl{width:100%;border-collapse:collapse;margin:12px 0;font-size:14px;} 73 .tbl th{text-align:left;color:var(--text2);font-size:11px;text-transform:uppercase;letter-spacing:.5px;padding:8px 10px;border-bottom:1px solid var(--border2);font-weight:700;} 74 .tbl td{padding:8px 10px;border-bottom:1px solid var(--border);color:var(--text2);} 75 .tbl td:first-child{color:var(--text);font-family:monospace;font-size:13px;} 76 77 /* ARCH */ 78 .arch-box{background:var(--code-bg);border:1px solid var(--border);border-radius:10px;padding:20px;overflow-x:auto;} 79 .arch-box pre{color:var(--text2);font-size:12px;line-height:1.5;white-space:pre;} 80 81 /* LINKS GRID */ 82 .links-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:14px;margin-bottom:40px;} 83 .link-card{background:var(--card);border:1px solid var(--border);border-radius:10px;padding:18px;transition:all .2s;text-decoration:none;color:var(--text);} 84 .link-card:hover{border-color:var(--orange);transform:translateY(-2px);text-decoration:none;} 85 .link-card h3{font-size:15px;margin-bottom:4px;} 86 .link-card p{font-size:13px;color:var(--text2);} 87 .link-card .arrow{color:var(--orange);font-size:14px;} 88 89 /* CHANGELOG */ 90 .cl-item{border-left:3px solid var(--border2);padding-left:18px;margin-bottom:24px;transition:border-color .2s;} 91 .cl-item:hover{border-left-color:var(--orange);} 92 .cl-head{display:flex;align-items:center;gap:10px;margin-bottom:4px;flex-wrap:wrap;} 93 .cl-head h3{font-size:17px;} 94 .cl-ver{color:var(--orange);font-weight:700;font-size:13px;background:rgba(255,107,53,.1);padding:2px 8px;border-radius:4px;} 95 .cl-date{color:var(--text3);font-size:13px;} 96 .cl-item ul{list-style:none;padding:0;} 97 .cl-item li{color:var(--text2);padding:3px 0 3px 16px;position:relative;font-size:14px;} 98 .cl-item li::before{content:'';width:5px;height:5px;border-radius:50%;background:var(--orange);position:absolute;
98left:2px;top:11px;} 99 100 /* FOOTER */ 101 .footer{text-align:center;padding:40px 20px;color:var(--text3);font-size:13px;border-top:1px solid var(--border);margin-top:40px;} 102 .footer a{color:var(--text2);} 103 104 @media(max-width:768px){ 105 .hero{padding:40px 16px 30px;} 106 .hero h1{font-size:26px;} 107 .hero .tagline{font-size:15px;} 108 .nav{padding:8px 14px;} 109 .nav-links{gap:14px;} 110 .grid-3{grid-template-columns:1fr;} 111 .grid-2{grid-template-columns:1fr;} 112 .section{padding:0 14px;} 113 .section-title{font-size:20px;} 114 } 115 </style> 116<link rel="stylesheet" href="/css/site-layout.css"></head> 117<body> 118 <nav class="nav"> 119 <a href="/" class="nav-brand"><img src="/images/icon-haloween.jpg" alt="Logo"> The Black Hole Bay</a> 120 <div class="nav-links"> 121 <a href="/">Docs</a> 122 <a href="/api">API</a> 123 <a href="/" data-main-site>Main Site</a> 124 </div> 125 </nav> 126 127 <div class="hero"> 128 <img src="/images/icon-haloween.jpg" alt="The Black Hole Bay" class="hero-logo"> 129 <h1>The Black Hole Bay</h1> 130 <p class="tagline">A fast, DHT-powered torrent search engine and community platform. Built with vanilla Node.js, zero dependencies, and a public REST API for developers.</p> 131 <div class="badges"> 132 <span class="badge"><b>REST</b> API</span> 133 <span class="badge"><b>User</b> Accounts</span> 134 <span class="badge"><b>XP & Levels</b></span> 135 <span class="badge"><b>DHT</b> Crawler</span> 136 <span class="badge"><b>JSON</b> Responses</span> 137 <span class="badge"><b>Zero</b> Dependencies</span> 138 </div> 139 <div class="hero-cta"> 140 <a href="/api" class="btn btn-primary"> 141 <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M9.4 16.6L4.8 12l4.6-4.6L8 6l-6 6 6 6 1.4-1.4zm5.2 0L19.2 12l-4.6-4.6L16 6l6 6-6 6-1.4-1.4z"/></svg> 142 API Reference 143 </a> 144 <a href="#quickstart" class="btn btn-ghost">Quick Start</a> 145 </div> 146 </div> 147 148 <div class="section" style="margin-bottom:40px;"> 149 <div class="section-title"><span class="bar"></span> What is it?</div> 150 <p style="color:var(--text2);font-size:16px;margin-bottom:12px;">The Black Hole Bay is a self-hosted, highly optimized torrent search engine and community platform. It crawls the BitTorrent DHT network, aggregates results from TPB, 1337x, and YTS, and allows users to create accounts, upload torrents, rate each other, and earn XP to level up their trust rank.</p> 151 <div class="grid grid-3"> 152 <div class="fcard"><div class="fcard-icon"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M15.5 14h-.79l-.28-.27A6.471 6.471 0 0016 9.5 6.5 6.5 0 109.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/></svg></div><h3>Hybrid Torrent Search</h3><p>Searches TPB, 1337x, YTS, and our local DHT index simultaneously. Results are merged, deduplicated, and served with ready-to-use magnet links.</p></div> 153 <div class="fcard"><div class="fcard-icon"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/></svg></div><h3>Community & Uploads</h3><p>User accounts with XP, Trust Levels (1-10), and profile badges. Users can upload new torrents directly to the index and rate each other.</p></div> 154 <div class="fcard"><div class="fcard-icon"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M19 5v14H5V5h14m0-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z"/></svg></div><h3>Dynamic File Lists</h3><p>For user-uploaded torrents, we fetch the file list dynamically directly from the BitTorrent network using WebTorrent.</p></div> 155 <div class="fcard"><div class="fcard-icon"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M21 6H3c-1.1 0-2 .9-2 2v8c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zM8 13H6v2H5v-2H3v-1h2v-2h1v2h2v1zm6.5 2c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm3.5-3c-.83 0-1.5-.67-1.5-1.5S16.67 9 17.5 9s1.5.67 1.5 1.5-.67 1.5-1.5 1.5z"/></svg></div><h3>Games & Media</h3><p>Trending movies, now-playing listings, popular TV shows, and recently released games from TMDB and RAWG.</p></div> 156 <div class="fcard"><div class="fcard-icon"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/></svg></div><h3>Rate Limiting</h3><p>Automatic IP-based rate limiting at 120 requests per minute (5/min for auth) with 429 responses and exponential backoff guidance.</p></div> 157 <div class="fcard"><div class="fcard-icon"><svg viewBox="0 0 24 24" fill="currentColor">
157<path d="M12 1L3 5v6c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12V5l-9-4z"/></svg></div><h3>Security</h3><p>scrypt password hashing, session token auth, illegal content auto-ban, strict CSP headers, and file upload validation (magic bytes).</p></div> 158 </div> 159 </div> 160 161 <div class="section" id="quickstart" style="margin-bottom:40px;"> 162 <div class="section-title"><span class="bar"></span> Quick Start</div> 163 <p style="color:var(--text2);margin-bottom:12px;">Base URL: <code style="color:var(--orange);" id="base-url"></code></p> 164 <p style="color:var(--text2);margin-bottom:8px;">No signup required for search. Just send requests.</p> 165 <div class="code-block"> 166 <div class="code-head"><span class="code-lang">bash</span><button class="copy-btn" onclick="copyCode(this)">Copy</button></div> 167 <div class="code-body"><code># Search torrents 168curl "<span class="api-url" data-path="/api/search?q=breaking+bad&category=200"></span>" 169 170# Trending movies 171curl "<span class="api-url" data-path="/api/trending"></span>" 172 173# Get user profile 174curl "<span class="api-url" data-path="/api/user/profile/Cybotage"></span>"</code></div> 175 </div> 176 <p style="color:var(--text2);margin-top:8px;">Every endpoint returns JSON. See the <a href="/api">full API reference</a> for all endpoints, parameters, and response schemas.</p> 177 </div> 178 179 <div class="section" style="margin-bottom:40px;"> 180 <div class="section-title"><span class="bar"></span> Architecture</div> 181 <div class="arch-box"><pre> +---------------------+ 182 | Client / App | 183 | Web - Mobile - Bot | 184 +---------------------+ 185 | 186 v 187 +---------------------+ 188 | The Black Hole Bay | 189 | REST API | 190 +---------------------+ 191 | 192 +-----------------+-----------------+ 193 | | | 194 v v v 195 +------------+ +------------+ +------------+ 196 | Torrent | | Media | | Game | 197 | Network | | Metadata | | Data | 198 +------------+ +------------+ +------------+</pre></div> 199 <p style="color:var(--text2);margin-top:12px;">The API normalizes data from all providers into simple JSON responses. Clients consume one API instead of integrating multiple services directly.</p> 200 </div> 201 202 <div class="section" style="margin-bottom:40px;"> 203 <div class="section-title"><span class="bar"></span> Announcements</div> 204 <div id="announcements-list"><p style="color:var(--text2);">Loading...</p></div> 205 </div> 206 207 <div class="section" style="margin-bottom:40px;"> 208 <div class="section-title"><span class="bar"></span> Data Providers</div> 209 <table class="tbl"> 210 <tr><th>Provider</th><th>Used For</th><th>Key Required</th></tr> 211 <tr><td>TMDB</td><td>Movies and TV metadata</td><td>Yes (server-side)</td></tr> 212 <tr><td>RAWG</td><td>Game metadata</td><td>Yes (server-side)</td></tr> 213 <tr><td>Pirate Bay API</td><td>Torrent search data</td><td>No</td></tr> 214 <tr><td>Nyaa</td><td>Search and RSS results</td><td>No</td></tr> 215 <tr><td>YTS.mx</td><td>Movie torrents (high seeders)</td><td>No</td></tr> 216 <tr><td>EZTV</td><td>TV search and RSS results</td><td>No</td></tr> 217 <tr><td>FitGirl Repacks</td><td>Game releases via RSS</td><td>No</td></tr> 218 <tr><td>SubsPlease</td><td>Anime releases via JSON API</td><td>No</td></tr> 219 <tr><td>1337x</td><td>Torrent search (fallback)</td><td>No</td></tr> 220 <tr><td>DHT Network</td><td>BitTorrent crawler</td><td>No</td></tr> 221 <tr><td>Local Index</td><td>Cached torrents & user uploads</td><td>No</td></tr> 222 </table> 223 </div> 224 225 <div class="section" style="margin-bottom:40px;"> 226 <div class="section-title"><span class="bar"></span> Quick Links</div> 227 <div class="links-grid"> 228 <a href="/api" class="link-card"><h3>API Reference</h3><p>Full endpoint documentation with parameters, responses, and code examples</p><span class="arrow">-></span></a> 229 <a href="/" data-main-site class="link-card"><h3>Search Torrents</h3><p>Go to the main site and start searching for torrents</p><span class="arrow">-></span></a> 230 <a href="/upcoming.html" data-main-site class="link-card"><h3>Upcoming Releases</h3><p>Browse trending movies, TV shows, and games</p><span class="arrow">-></span></a> 231 </div> 232 </div> 233 234 <div class="footer"> 235 <p>The Black Hole Bay - Documentation & API Reference</p> 236 <p style="margin-top:4px;">Last updated: October 7, 2026</p> 237 <p style="margin-top:8px;"><a href="/" data-main-site>Main Site</a> - <a href="/api">API</a> - <a href="#quickstart">Quick Start</a> - <a href="https://discord.gg/Qb2GQqW3Uq" target="_blank" rel="noopener noreferrer">Discord</a> - <a href="/#donations" data-main-site>Donations</a></p> 238 </div> 239 240
240<script> 241 function copyCode(btn){ 242 var code=btn.closest('.code-block').querySelector('code').textContent; 243 navigator.clipboard.writeText(code).then(function(){ 244 btn.textContent='Copied!';btn.classList.add('copied'); 245 setTimeout(function(){btn.textContent='Copy';btn.classList.remove('copied');},2000); 246 }); 247 } 248 function esc(s){return String(s||'').replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');} 249 250 // Resolve the public API base at runtime instead of hardcoding a hostname. 251 // On the docs subdomain the main site is the parent domain; everywhere else 252 // (localhost, 127.0.0.1, the main domain) the current origin *is* the site. 253 (function(){ 254 var host = window.location.hostname; 255 var base; 256 if (host.indexOf('docs.') === 0) { 257 base = window.location.protocol + '//' + host.replace(/^docs\./, ''); 258 } else { 259 base = window.location.origin; 260 } 261 var bu = document.getElementById('base-url'); 262 if (bu) bu.textContent = base; 263 Array.prototype.forEach.call(document.querySelectorAll('[data-main-site]'), function(a){ 264 a.setAttribute('href', base + a.getAttribute('href')); 265 }); 266 Array.prototype.forEach.call(document.querySelectorAll('.api-url'), function(s){ 267 s.textContent = base + s.getAttribute('data-path'); 268 }); 269 })(); 270 271 // Fetch Announcements 272 fetch('/api/announcements').then(r=>r.json()).then(data => { 273 if(data && data.length > 0) { 274 document.getElementById('announcements-list').innerHTML = data.map(p => ` 275 <div style="background:var(--card);border:1px solid var(--border);border-radius:10px;padding:18px;margin-bottom:14px;"> 276 <strong style="color:var(--text);font-size:15px;">${esc(p.title)}</strong> 277 <p style="color:var(--text2);font-size:14px;margin:6px 0 0 0;white-space:pre-wrap;">${esc(p.text)}</p> 278 </div> 279 `).join(''); 280 } else { 281 document.getElementById('announcements-list').innerHTML = '<p style="color:var(--text2);">No announcements yet.</p>'; 282 } 283 }).catch(() => { 284 document.getElementById('announcements-list').innerHTML = '<p style="color:var(--text2);">Failed to load announcements.</p>'; 285 }); 286 </script>
vendor: 1 bytes, line 286
286
287<script defer src="/js/site-footer.js"></script>
287<script type="module" src="https://static.cloudflareinsights.com/beacon.min.js/v4bc70e2c01a94c73b74392e4234840661791215815920" integrity="sha512-L0ha0OXavK/8okipN9F8BtP84dg9DUhPERbBXzwI6dgTA55d2+yweo3pn5CSFYs45/r8md2+xvUPtTdvTNRfjA==" data-cf-beacon='{"version":"2024.11.0","token":"fed1a331b87d4dc7b361c56f56c914c2","r":1,"spa":2}' crossorigin="anonymous"></script>
287 288</body> 289</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.