Roblox'ta Sahipsiz (Boş) Gruplar Nasıl Bulunur?

Konuyu başlatankyr karacaMod·
Yanıt
0
Görüntülenme
0
Oy
0
Son yanıt
Henüz yok
0 görüntülenme

Roblox'ta Sahipsiz (Boş) Gruplar Nasıl Bulunur?

Roblox dünyasında, kurucusu ayrılmış ve şu an bir sahibi olmayan "boş" grupları bulmak, topluluk yönetmek veya nadir isimli gruplara sahip olmak isteyenler için oldukça popülerdir. İşte profesyonel bir tarama uygulaması mantığıyla bu işlemin nasıl yapılacağı:

1. Adım: Tarama Aralığını Belirleme (ID Keşfi)

Roblox'taki her grubun benzersiz bir ID numarası vardır. Tarama işlemine başlamadan önce hangi aralıkta arama yapacağınızı seçmelisiniz.

  • Eski Gruplar: Daha düşük ID numaraları (örneğin: 100.000 - 500.000 arası).
  • Yeni Gruplar: Daha yüksek ID numaraları (10.000.000 ve üzeri).

Strateji: Başlangıç ve bitiş ID'sini belirleyerek tarayıcıyı bu aralığa odaklayın.

"Eski gruplar için tarama aralığını daha düşük ID'lere odaklamak, daha iyi sonuçlar elde etmenize yardımcı olabilir."

2. Adım: Tarama Hızı ve Performans Ayarları

Uygulamanın Roblox API'lerini ne kadar hızlı sorgulayacağını seçin:

  • Yavaş: IP ban riskini en aza indirir, daha güvenlidir.
  • Orta: Dengeli bir arama sağlar.
  • Hızlı: Çok sayıda grubu saniyeler içinde kontrol eder (Proxy kullanımı gerektirebilir).

3. Adım: Akıllı Filtreleme

Binlerce grup arasından işinize yarayanları bulmak için şu filtreleri uygulamanız şarttır:

  • Sahipsiz mi? (No Owner): Grubun "Owner" kısmının boş olduğundan emin olun.
  • Üye Sayısı: İçinde hala üyelerin olduğu veya tamamen boş olan grupları seçin.
  • Katılım Durumu: Grubun "Public" (herkese açık) olup olmadığını kontrol edin. Eğer grup sahipsiz ve "Public" ise tek tıkla yeni sahibi siz olabilirsiniz!
  • Grup Fonu (Funds): Grubun içinde Robux olup olmadığını kontrol eden gelişmiş filtreleri aktif edin.

4. Adım: Tarama Süreci ve Takip

Uygulama üzerinden taramayı başlatın. Bu aşamada panel size şunları göstermelidir:

  • Şu an taranan ID.
  • Bulunan potansiyel boş gruplar.
  • Hatalı veya kapalı ID'ler.

5. Adım: Verileri Dışa Aktarma (Export)

Bulduğunuz değerli grupları kaybetmemek için listeyi CSV veya TXT formatında dışa aktarın. Bu sayede daha sonra tek tek bu gruplara gidip durumlarını kontrol edebilirsiniz.

Bazı İpuçları

  • Grup İsimleri: Genellikle eski grupların isimleri çok daha kısa ve değerlidir. Tarama aralığınızı eski ID'lere göre ayarlayın.
  • Katılım Şartı: Bir grubun sahibi olmak için Roblox üzerinde Premium üyeliğinizin olması gerekebilir.
  • Güvenlik: Tarama yaparken hesabınızın güvenliği için ana hesabınız yerine bir "alt hesap" (yan hesap) kullanmanız önerilir.

🛠️ Uygulamanın Teknik Bileşenleri

  • Tarama Paneli: Operasyonun merkezi.
  • Filtreleme Paneli: Kriterlerin belirlendiği filtre süzgeci.
  • Export Paneli: Sonuçların hasat edildiği bölüm.

Uygulama İçinden Fotoğraflar

Görsel

İşte Hazır Kulana Biliceğiniz Bir Kod Parçası(HTML)

<html lang="tr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Roblox Empty Group Finder</title>
<link href="https://fonts.googleapis.com/css2?family=Rajdhani:wght@400;500;600;700&family=Share+Tech+Mono&family=Exo+2:wght@300;400;600;800&display=swap" rel="stylesheet">
<style>
  :root {
    --bg: #050a0f;
    --surface: #0a1520;
    --surface2: #0f1e2e;
    --border: #1a3a5c;
    --accent: #00d4ff;
    --accent2: #ff4d6d;
    --accent3: #39ff14;
    --text: #c8e6f5;
    --muted: #4a7a9b;
    --gold: #ffd700;
    --glow: 0 0 20px rgba(0,212,255,0.3);
    --glow2: 0 0 20px rgba(57,255,20,0.3);
  }

  * { margin: 0; padding: 0; box-sizing: border-box; }

  body {
    background: var(--bg);
    color: var(--text);
    font-family: 'Exo 2', sans-serif;
    min-height: 100vh;
    overflow-x: hidden;
  }

  /* Grid background */
  body::before {
    content: '';
    position: fixed;
    inset: 0;
    background-image:
      linear-gradient(rgba(0,212,255,0.03) 1px, transparent 1px),
      linear-gradient(90deg, rgba(0,212,255,0.03) 1px, transparent 1px);
    background-size: 40px 40px;
    pointer-events: none;
    z-index: 0;
  }

  /* Scanline effect */
  body::after {
    content: '';
    position: fixed;
    inset: 0;
    background: repeating-linear-gradient(
      0deg,
      transparent,
      transparent 2px,
      rgba(0,0,0,0.05) 2px,
      rgba(0,0,0,0.05) 4px
    );
    pointer-events: none;
    z-index: 1;
  }

  .container {
    position: relative;
    z-index: 2;
    max-width: 1200px;
    margin: 0 auto;
    padding: 20px;
  }

  /* HEADER */
  header {
    text-align: center;
    padding: 30px 0 20px;
    position: relative;
  }

  .logo-line {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 15px;
    margin-bottom: 8px;
  }

  .logo-icon {
    width: 48px;
    height: 48px;
    background: linear-gradient(135deg, var(--accent), #0080ff);
    clip-path: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 20px;
    animation: pulse 2s infinite;
    box-shadow: var(--glow);
  }

  @keyframes pulse {
    0%, 100% { box-shadow: 0 0 20px rgba(0,212,255,0.3); }
    50% { box-shadow: 0 0 40px rgba(0,212,255,0.7); }
  }

  h1 {
    font-family: 'Rajdhani', sans-serif;
    font-size: clamp(28px, 5vw, 52px);
    font-weight: 700;
    letter-spacing: 4px;
    text-transform: uppercase;
    background: linear-gradient(90deg, var(--accent), #fff, var(--accent));
    background-size: 200%;
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    animation: shimmer 3s infinite;
  }

  @keyframes shimmer {
    0% { background-position: 0%; }
    100% { background-position: 200%; }
  }

  .subtitle {
    font-family: 'Share Tech Mono', monospace;
    color: var(--muted);
    font-size: 12px;
    letter-spacing: 3px;
  }

  .divider {
    height: 1px;
    background: linear-gradient(90deg, transparent, var(--accent), transparent);
    margin: 20px 0;
    opacity: 0.4;
  }

  /* STATS BAR */
  .stats-bar {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 12px;
    margin-bottom: 20px;
  }

  .stat-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-top: 2px solid var(--accent);
    padding: 14px 16px;
    position: relative;
    overflow: hidden;
    clip-path: polygon(0 0, calc(100% - 12px) 0, 100% 12px, 100% 100%, 12px 100%, 0 calc(100% - 12px));
  }

  .stat-card::before {
    content: '';
    position: absolute;
    top: 0; left: 0; right: 0;
    height: 2px;
    background: linear-gradient(90deg, var(--accent), transparent);
  }

  .stat-label {
    font-family: 'Share Tech Mono', monospace;
    font-size: 10px;
    color: var(--muted);
    letter-spacing: 2px;
    text-transform: uppercase;
    margin-bottom: 6px;
  }

  .stat-value {
    font-family: 'Rajdhani', sans-serif;
    font-size: 26px;
    font-weight: 700;
    color: var(--accent);
    line-height: 1;
  }

  .stat-value.green { color: var(--accent3); }
  .stat-value.red { color: var(--accent2); }
  .stat-value.gold { color: var(--gold); }

  /* MAIN LAYOUT */
  .main-grid {
    display: grid;
    grid-template-columns: 300px 1fr;
    gap: 16px;
  }

  /* CONTROL PANEL */
  .panel {
    background: var(--surface);
    border: 1px solid var(--border);
    padding: 20px;
    position: relative;
  }

  .panel::before {
    content: '';
    position: absolute;
    top: 0; left: 0; right: 0;
    height: 2px;
    background: linear-gradient(90deg, var(--accent), var(--accent2));
  }

  .panel-title {
    font-family: 'Rajdhani', sans-serif;
    font-size: 14px;
    font-weight: 600;
    letter-spacing: 3px;
    text-transform: uppercase;
    color: var(--accent);
    margin-bottom: 18px;
    display: flex;
    align-items: center;
    gap: 8px;
  }

  .panel-title::before {
    content: '';
    width: 6px;
    height: 6px;
    background: var(--accent);
    transform: rotate(45deg);
    display: block;
  }

  /* FORM ELEMENTS */
  .form-group {
    margin-bottom: 16px;
  }

  label {
    display: block;
    font-family: 'Share Tech Mono', monospace;
    font-size: 10px;
    color: var(--muted);
    letter-spacing: 2px;
    text-transform: uppercase;
    margin-bottom: 6px;
  }

  input[type="number"], select {
    width: 100%;
    background: var(--bg);
    border: 1px solid var(--border);
    color: var(--text);
    padding: 10px 12px;
    font-family: 'Share Tech Mono', monospace;
    font-size: 13px;
    outline: none;
    transition: border-color 0.2s;
    appearance: none;
  }

  input[type="number"]:focus, select:focus {
    border-color: var(--accent);
    box-shadow: 0 0 10px rgba(0,212,255,0.1);
  }

  .range-group {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
  }

  /* TOGGLE */
  .toggle-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 12px;
    padding: 8px 0;
    border-bottom: 1px solid rgba(26,58,92,0.4);
  }

  .toggle-label {
    font-size: 12px;
    color: var(--text);
  }

  .toggle {
    position: relative;
    width: 40px;
    height: 20px;
  }

  .toggle input { display: none; }

  .toggle-slider {
    position: absolute;
    inset: 0;
    background: var(--bg);
    border: 1px solid var(--border);
    cursor: pointer;
    transition: 0.3s;
  }

  .toggle-slider::after {
    content: '';
    position: absolute;
    width: 14px;
    height: 14px;
    left: 3px;
    top: 2px;
    background: var(--muted);
    transition: 0.3s;
  }

  .toggle input:checked + .toggle-slider {
    background: rgba(0,212,255,0.1);
    border-color: var(--accent);
  }

  .toggle input:checked + .toggle-slider::after {
    transform: translateX(18px);
    background: var(--accent);
    box-shadow: 0 0 8px var(--accent);
  }

  /* BUTTONS */
  .btn {
    width: 100%;
    padding: 14px;
    font-family: 'Rajdhani', sans-serif;
    font-size: 15px;
    font-weight: 700;
    letter-spacing: 3px;
    text-transform: uppercase;
    cursor: pointer;
    transition: all 0.2s;
    border: none;
    position: relative;
    overflow: hidden;
  }

  .btn-primary {
    background: linear-gradient(135deg, #0060a0, var(--accent));
    color: #000;
    clip-path: polygon(8px 0, 100% 0, calc(100% - 8px) 100%, 0 100%);
  }

  .btn-primary:hover {
    background: linear-gradient(135deg, var(--accent), #00ffff);
    box-shadow: var(--glow);
    transform: translateY(-1px);
  }

  .btn-primary:disabled {
    background: var(--border);
    color: var(--muted);
    cursor: not-allowed;
    transform: none;
    box-shadow: none;
  }

  .btn-danger {
    background: transparent;
    color: var(--accent2);
    border: 1px solid var(--accent2);
    margin-top: 8px;
    clip-path: polygon(8px 0, 100% 0, calc(100% - 8px) 100%, 0 100%);
  }

  .btn-danger:hover {
    background: rgba(255,77,109,0.1);
    box-shadow: 0 0 15px rgba(255,77,109,0.2);
  }

  .btn-danger:disabled {
    opacity: 0.3;
    cursor: not-allowed;
  }

  /* PROGRESS */
  .progress-section {
    margin-top: 16px;
  }

  .progress-header {
    display: flex;
    justify-content: space-between;
    font-family: 'Share Tech Mono', monospace;
    font-size: 10px;
    color: var(--muted);
    margin-bottom: 6px;
  }

  .progress-bar {
    height: 6px;
    background: var(--bg);
    border: 1px solid var(--border);
    overflow: hidden;
  }

  .progress-fill {
    height: 100%;
    background: linear-gradient(90deg, var(--accent), var(--accent3));
    width: 0%;
    transition: width 0.3s;
    box-shadow: var(--glow2);
  }

  .status-text {
    font-family: 'Share Tech Mono', monospace;
    font-size: 10px;
    color: var(--accent3);
    margin-top: 8px;
    min-height: 14px;
    animation: blink 1s infinite;
  }

  @keyframes blink {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.5; }
  }

  .status-text.idle { color: var(--muted); animation: none; }
  .status-text.error { color: var(--accent2); animation: none; }

  /* SPEED SELECTOR */
  .speed-btns {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 6px;
  }

  .speed-btn {
    padding: 8px;
    background: var(--bg);
    border: 1px solid var(--border);
    color: var(--muted);
    font-family: 'Share Tech Mono', monospace;
    font-size: 11px;
    cursor: pointer;
    text-align: center;
    transition: all 0.2s;
  }

  .speed-btn.active {
    background: rgba(0,212,255,0.1);
    border-color: var(--accent);
    color: var(--accent);
  }

  /* RESULTS PANEL */
  .results-panel {
    display: flex;
    flex-direction: column;
    gap: 12px;
  }

  /* FILTER BAR */
  .filter-bar {
    background: var(--surface);
    border: 1px solid var(--border);
    padding: 14px 16px;
    display: flex;
    gap: 12px;
    align-items: center;
    flex-wrap: wrap;
  }

  .filter-bar input {
    background: var(--bg);
    border: 1px solid var(--border);
    color: var(--text);
    padding: 8px 12px;
    font-family: 'Share Tech Mono', monospace;
    font-size: 12px;
    outline: none;
    flex: 1;
    min-width: 150px;
  }

  .filter-bar input:focus { border-color: var(--accent); }

  .sort-select {
    background: var(--bg);
    border: 1px solid var(--border);
    color: var(--text);
    padding: 8px 12px;
    font-family: 'Share Tech Mono', monospace;
    font-size: 11px;
    outline: none;
    cursor: pointer;
  }

  .export-btn {
    padding: 8px 16px;
    background: rgba(57,255,20,0.1);
    border: 1px solid var(--accent3);
    color: var(--accent3);
    font-family: 'Share Tech Mono', monospace;
    font-size: 11px;
    cursor: pointer;
    letter-spacing: 1px;
    transition: all 0.2s;
  }

  .export-btn:hover {
    background: rgba(57,255,20,0.2);
    box-shadow: var(--glow2);
  }

  /* GROUP LIST */
  .group-list {
    background: var(--surface);
    border: 1px solid var(--border);
    min-height: 400px;
    max-height: 600px;
    overflow-y: auto;
    padding: 12px;
    display: flex;
    flex-direction: column;
    gap: 8px;
  }

  .group-list::-webkit-scrollbar { width: 4px; }
  .group-list::-webkit-scrollbar-track { background: var(--bg); }
  .group-list::-webkit-scrollbar-thumb { background: var(--border); }
  .group-list::-webkit-scrollbar-thumb:hover { background: var(--accent); }

  /* EMPTY STATE */
  .empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    height: 350px;
    color: var(--muted);
    text-align: center;
    gap: 12px;
  }

  .empty-icon {
    font-size: 48px;
    opacity: 0.3;
  }

  .empty-text {
    font-family: 'Share Tech Mono', monospace;
    font-size: 12px;
    letter-spacing: 2px;
  }

  /* GROUP CARD */
  .group-card {
    background: var(--bg);
    border: 1px solid var(--border);
    border-left: 3px solid var(--accent3);
    padding: 14px 16px;
    display: flex;
    align-items: center;
    gap: 14px;
    cursor: pointer;
    transition: all 0.2s;
    animation: slideIn 0.3s ease;
    position: relative;
    overflow: hidden;
  }

  @keyframes slideIn {
    from { opacity: 0; transform: translateX(-10px); }
    to { opacity: 1; transform: translateX(0); }
  }

  .group-card:hover {
    border-color: var(--accent);
    border-left-color: var(--accent);
    background: rgba(0,212,255,0.03);
    box-shadow: var(--glow);
  }

  .group-card::after {
    content: '';
    position: absolute;
    top: 0; left: 0;
    width: 100%;
    height: 100%;
    background: linear-gradient(135deg, rgba(0,212,255,0.03), transparent);
    pointer-events: none;
  }

  .group-id {
    font-family: 'Share Tech Mono', monospace;
    font-size: 11px;
    color: var(--muted);
    min-width: 80px;
  }

  .group-info { flex: 1; }

  .group-name {
    font-family: 'Rajdhani', sans-serif;
    font-size: 16px;
    font-weight: 600;
    color: var(--text);
    margin-bottom: 3px;
  }

  .group-meta {
    font-family: 'Share Tech Mono', monospace;
    font-size: 10px;
    color: var(--muted);
    display: flex;
    gap: 14px;
  }

  .group-meta span { display: flex; align-items: center; gap: 4px; }

  .badge {
    padding: 3px 10px;
    font-family: 'Share Tech Mono', monospace;
    font-size: 10px;
    letter-spacing: 1px;
    font-weight: 600;
  }

  .badge-open {
    background: rgba(57,255,20,0.15);
    border: 1px solid var(--accent3);
    color: var(--accent3);
  }

  .badge-locked {
    background: rgba(255,77,109,0.15);
    border: 1px solid var(--accent2);
    color: var(--accent2);
  }

  .badge-zero {
    background: rgba(255,215,0,0.15);
    border: 1px solid var(--gold);
    color: var(--gold);
  }

  .group-link {
    font-family: 'Share Tech Mono', monospace;
    font-size: 10px;
    color: var(--accent);
    text-decoration: none;
    padding: 5px 10px;
    border: 1px solid rgba(0,212,255,0.3);
    transition: all 0.2s;
    white-space: nowrap;
  }

  .group-link:hover {
    background: rgba(0,212,255,0.1);
    box-shadow: var(--glow);
  }

  /* LOG SECTION */
  .log-section {
    background: var(--surface);
    border: 1px solid var(--border);
    padding: 12px;
    max-height: 120px;
    overflow-y: auto;
  }

  .log-title {
    font-family: 'Share Tech Mono', monospace;
    font-size: 10px;
    color: var(--muted);
    letter-spacing: 2px;
    margin-bottom: 8px;
  }

  .log-entry {
    font-family: 'Share Tech Mono', monospace;
    font-size: 10px;
    color: var(--muted);
    margin-bottom: 3px;
    display: flex;
    gap: 8px;
  }

  .log-time { color: rgba(0,212,255,0.4); }
  .log-found { color: var(--accent3); }
  .log-skip { color: var(--muted); }
  .log-err { color: var(--accent2); }

  /* CORS NOTE */
  .cors-note {
    background: rgba(255,215,0,0.05);
    border: 1px solid rgba(255,215,0,0.3);
    border-left: 3px solid var(--gold);
    padding: 10px 14px;
    font-family: 'Share Tech Mono', monospace;
    font-size: 10px;
    color: rgba(255,215,0,0.8);
    letter-spacing: 1px;
    line-height: 1.6;
  }

  /* RESPONSIVE */
  @media (max-width: 768px) {
    .main-grid { grid-template-columns: 1fr; }
    .stats-bar { grid-template-columns: repeat(2, 1fr); }
  }
</style>
</head>
<body>
<div class="container">
  <header>
    <div class="logo-line">
      <div class="logo-icon">⬡</div>
      <h1>Group Scanner</h1>
    </div>
    <div class="subtitle">ROBLOX EMPTY GROUP FINDER v2.0</div>
  </header>

  <div class="divider"></div>

  <!-- STATS BAR -->
  <div class="stats-bar">
    <div class="stat-card">
      <div class="stat-label">Taranan</div>
      <div class="stat-value" id="stat-scanned">0</div>
    </div>
    <div class="stat-card">
      <div class="stat-label">Bulunan</div>
      <div class="stat-value green" id="stat-found">0</div>
    </div>
    <div class="stat-card">
      <div class="stat-label">Hata</div>
      <div class="stat-value red" id="stat-error">0</div>
    </div>
    <div class="stat-card">
      <div class="stat-label">Süre</div>
      <div class="stat-value gold" id="stat-time">0s</div>
    </div>
  </div>

  <!-- CORS NOTE -->
  <div class="cors-note" id="cors-note">
    ⚠ NOT: Roblox API'si tarayıcıdan doğrudan erişime izin vermiyor (CORS). Simülasyon modu aktif — gerçek tarama için bir browser eklentisi veya proxy kullanman gerekebilir. Demo verisiyle çalışmak için <strong>Simüle Et</strong> butonunu kullan.
  </div>

  <div style="height:12px"></div>

  <div class="main-grid">
    <!-- CONTROL PANEL -->
    <div class="panel">
      <div class="panel-title">Kontrol Paneli</div>

      <div class="form-group">
        <label>ID Aralığı</label>
        <div class="range-group">
          <input type="number" id="id-start" value="1" min="1" placeholder="Başlangıç">
          <input type="number" id="id-end" value="50000" min="1" placeholder="Bitiş">
        </div>
      </div>

      <div class="form-group">
        <label>Tarama Hızı</label>
        <div class="speed-btns">
          <button class="speed-btn active" data-delay="800">YAVAŞ</button>
          <button class="speed-btn" data-delay="400">ORTA</button>
          <button class="speed-btn" data-delay="100">HIZLI</button>
        </div>
      </div>

      <div class="form-group">
        <label>Filtreler</label>
        <div class="toggle-row">
          <span class="toggle-label">Sadece 0 üye</span>
          <label class="toggle">
            <input type="checkbox" id="filter-zero" checked>
            <span class="toggle-slider"></span>
          </label>
        </div>
        <div class="toggle-row">
          <span class="toggle-label">Herkese açık gruplar</span>
          <label class="toggle">
            <input type="checkbox" id="filter-open" checked>
            <span class="toggle-slider"></span>
          </label>
        </div>
        <div class="toggle-row">
          <span class="toggle-label">Sahipsiz gruplar</span>
          <label class="toggle">
            <input type="checkbox" id="filter-ownerless" checked>
            <span class="toggle-slider"></span>
          </label>
        </div>
        <div class="toggle-row">
          <span class="toggle-label">Log kayıtları</span>
          <label class="toggle">
            <input type="checkbox" id="toggle-log" checked>
            <span class="toggle-slider"></span>
          </label>
        </div>
      </div>

      <div class="form-group">
        <label>Maksimum Sonuç</label>
        <input type="number" id="max-results" value="50" min="1" max="500">
      </div>

      <button class="btn btn-primary" id="btn-start" onclick="startScan()">▶ Taramayı Başlat</button>
      <button class="btn btn-danger" id="btn-stop" onclick="stopScan()" disabled>■ Durdur</button>

      <div class="progress-section">
        <div class="progress-header">
          <span>İLERLEME</span>
          <span id="progress-pct">0%</span>
        </div>
        <div class="progress-bar">
          <div class="progress-fill" id="progress-fill"></div>
        </div>
        <div class="status-text idle" id="status-text">Bekleniyor...</div>
      </div>
    </div>

    <!-- RESULTS -->
    <div class="results-panel">
      <!-- Filter bar -->
      <div class="filter-bar">
        <input type="text" id="search-filter" placeholder="GRUP ARA..." oninput="filterResults()">
        <select class="sort-select" id="sort-select" onchange="sortResults()">
          <option value="found">Buluş Sırası</option>
          <option value="id-asc">ID (Artan)</option>
          <option value="id-desc">ID (Azalan)</option>
          <option value="name">İsim (A-Z)</option>
          <option value="members">Üye Sayısı</option>
        </select>
        <button class="export-btn" onclick="exportCSV()">⬇ CSV AKTAR</button>
        <button class="export-btn" onclick="copyIDs()" style="border-color:var(--accent);color:var(--accent);background:rgba(0,212,255,0.05)">⧉ ID KOPYALA</button>
      </div>

      <!-- Group list -->
      <div class="group-list" id="group-list">
        <div class="empty-state" id="empty-state">
          <div class="empty-icon">⬡</div>
          <div class="empty-text">TARAMA BAŞLATILMAYI BEKLİYOR</div>
          <div style="font-family:'Share Tech Mono',monospace;font-size:10px;color:var(--muted);margin-top:4px">Sol panelden ayarla ve başlat</div>
        </div>
      </div>

      <!-- Log -->
      <div class="log-section" id="log-section">
        <div class="log-title">// TARAMA KAYITLARI</div>
        <div id="log-entries"></div>
      </div>
    </div>
  </div>
</div>

<script>
  // State
  let scanning = false;
  let stopFlag = false;
  let foundGroups = [];
  let scanned = 0;
  let errors = 0;
  let startTime = null;
  let timerInterval = null;
  let scanDelay = 800;
  let currentId = 0;

  // Speed buttons
  document.querySelectorAll('.speed-btn').forEach(btn => {
    btn.addEventListener('click', function() {
      document.querySelectorAll('.speed-btn').forEach(b => b.classList.remove('active'));
      this.classList.add('active');
      scanDelay = parseInt(this.dataset.delay);
    });
  });

  function updateStats() {
    document.getElementById('stat-scanned').textContent = scanned;
    document.getElementById('stat-found').textContent = foundGroups.length;
    document.getElementById('stat-error').textContent = errors;
  }

  function updateTimer() {
    if (!startTime) return;
    const elapsed = Math.floor((Date.now() - startTime) / 1000);
    document.getElementById('stat-time').textContent = elapsed + 's';
  }

  function updateProgress() {
    const start = parseInt(document.getElementById('id-start').value) || 1;
    const end = parseInt(document.getElementById('id-end').value) || 50000;
    const total = end - start + 1;
    const done = currentId - start;
    const pct = total > 0 ? Math.min(100, Math.floor((done / total) * 100)) : 0;
    document.getElementById('progress-fill').style.width = pct + '%';
    document.getElementById('progress-pct').textContent = pct + '%';
  }

  function setStatus(msg, type = 'active') {
    const el = document.getElementById('status-text');
    el.textContent = msg;
    el.className = 'status-text ' + type;
  }

  function addLog(msg, type = 'skip') {
    if (!document.getElementById('toggle-log').checked) return;
    const now = new Date();
    const time = now.toTimeString().slice(0, 8);
    const entries = document.getElementById('log-entries');
    const div = document.createElement('div');
    div.className = 'log-entry';
    div.innerHTML = `<span class="log-time">[${time}]</span><span class="log-${type}">${msg}</span>`;
    entries.prepend(div);
    // Keep max 50 logs
    while (entries.children.length > 50) entries.lastChild.remove();
  }

  function addGroupCard(group) {
    const list = document.getElementById('group-list');
    const emptyState = document.getElementById('empty-state');
    if (emptyState) emptyState.remove();

    const card = document.createElement('div');
    card.className = 'group-card';
    card.dataset.id = group.id;
    card.dataset.name = group.name.toLowerCase();
    card.dataset.members = group.memberCount;

    const isOpen = group.publicEntryAllowed;
    const isZero = group.memberCount === 0;
    const hasOwner = group.owner !== null;

    let badges = '';
    if (isZero) badges += `<span class="badge badge-zero">0 ÜYE</span>`;
    if (isOpen) badges += `<span class="badge badge-open">AÇIK</span>`;
    else badges += `<span class="badge badge-locked">KAPALI</span>`;
    if (!hasOwner) badges += `<span class="badge" style="background:rgba(0,212,255,0.1);border:1px solid var(--accent);color:var(--accent)">SAHİPSİZ</span>`;

    card.innerHTML = `
      <div class="group-id">#${group.id}</div>
      <div class="group-info">
        <div class="group-name">${escapeHtml(group.name)}</div>
        <div class="group-meta">
          <span>👥 ${group.memberCount} üye</span>
          <span>🏅 ${group.owner ? escapeHtml(group.owner.username) : 'Sahipsiz'}</span>
          ${group.description ? `<span>📝 ${escapeHtml(group.description.slice(0,40))}${group.description.length > 40 ? '...' : ''}</span>` : ''}
        </div>
        <div style="margin-top:6px;display:flex;gap:6px;flex-wrap:wrap">${badges}</div>
      </div>
      <a href="https://www.roblox.com/groups/${group.id}" target="_blank" class="group-link" onclick="event.stopPropagation()">GÖRÜNTÜLE →</a>
    `;

    list.prepend(card);
  }

  function escapeHtml(text) {
    const d = document.createElement('div');
    d.appendChild(document.createTextNode(text || ''));
    return d.innerHTML;
  }

  function filterResults() {
    const query = document.getElementById('search-filter').value.toLowerCase();
    document.querySelectorAll('.group-card').forEach(card => {
      const name = card.dataset.name || '';
      const id = card.dataset.id || '';
      card.style.display = (name.includes(query) || id.includes(query)) ? '' : 'none';
    });
  }

  function sortResults() {
    const sort = document.getElementById('sort-select').value;
    const list = document.getElementById('group-list');
    const cards = Array.from(list.querySelectorAll('.group-card'));

    cards.sort((a, b) => {
      if (sort === 'id-asc') return parseInt(a.dataset.id) - parseInt(b.dataset.id);
      if (sort === 'id-desc') return parseInt(b.dataset.id) - parseInt(a.dataset.id);
      if (sort === 'name') return (a.dataset.name || '').localeCompare(b.dataset.name || '');
      if (sort === 'members') return parseInt(a.dataset.members) - parseInt(b.dataset.members);
      return 0;
    });

    cards.forEach(c => list.appendChild(c));
  }

  function exportCSV() {
    if (foundGroups.length === 0) { alert('Önce tarama yapın!'); return; }
    let csv = 'ID,İsim,Üye Sayısı,Açık,Sahipsiz,Roblox Linki\n';
    foundGroups.forEach(g => {
      csv += `${g.id},"${(g.name || '').replace(/"/g, '""')}",${g.memberCount},${g.publicEntryAllowed},${!g.owner},https://www.roblox.com/groups/${g.id}\n`;
    });
    const blob = new Blob([csv], { type: 'text/csv' });
    const a = document.createElement('a');
    a.href = URL.createObjectURL(blob);
    a.download = `roblox_empty_groups_${Date.now()}.csv`;
    a.click();
  }

  function copyIDs() {
    if (foundGroups.length === 0) { alert('Önce tarama yapın!'); return; }
    const ids = foundGroups.map(g => g.id).join('\n');
    navigator.clipboard.writeText(ids).then(() => {
      const btn = event.target;
      const orig = btn.textContent;
      btn.textContent = '✓ KOPYALANDI';
      setTimeout(() => btn.textContent = orig, 2000);
    });
  }

  // --- SIMULATION ENGINE ---
  // Since Roblox API has CORS restrictions, we simulate realistic data
  // In a real scenario, you'd use a CORS proxy or browser extension

  const sampleNames = [
    'The Shadow Guild', 'Noob Army', 'Pro Gamers', 'Dragon Clan', 'Builders United',
    'Roblox Veterans', 'Speed Runners', 'PVP Masters', 'The Lost Kingdom', 'Elite Squad',
    'Void Walkers', 'Storm Breakers', 'Night Owls', 'Pixel Warriors', 'Chaos Theory',
    'Silent Storm', 'Iron Shield', 'Golden Blaze', 'Crystal Vanguard', 'Neon Rebels',
    'Phantom Force', 'Sky Raiders', 'Terra Firma', 'Nexus Clan', 'Echo Chamber',
    'Apex Legends', 'Dark Matter', 'Solar Flare', 'Astral Guild', 'Quantum Shift'
  ];

  const descriptions = [
    'A group for serious players only.',
    '',
    'Join us for epic battles!',
    'We accept all skill levels.',
    '',
    'The best clan on Roblox.',
    '',
    'Est. 2019. Join and rise!',
    '',
    'Active daily. No toxicity.'
  ];

  async function generateFakeGroup(id) {
  const filterZero = document.getElementById('filter-zero').checked;
  const filterOpen = document.getElementById('filter-open').checked;
  const filterOwnerless = document.getElementById('filter-ownerless').checked;

  try {
    // Tarayıcıdan doğrudan Roblox'a istek atılamadığı için ücretsiz bir CORS proxy kullanıyoruz
    const targetUrl = `https://groups.roblox.com/v1/groups/${id}`;
    const proxyUrl = `https://api.allorigins.win/get?url=${encodeURIComponent(targetUrl)}`;
    
// fetchGroupData içindeki proxy satırını şununla değiştir:
const response = await fetch(`https://groups.roblox.com/v1/groups/${id}`);    
    // Proxy'den yanıt gelmezse veya rate limit yersek
    if (!response.ok) throw new Error("HTTP " + response.status);
    
    const proxyData = await response.json();
    const group = JSON.parse(proxyData.contents);

    // Grup yasaklanmışsa veya yoksa (API errors döndürür)
    if (group.errors) return null;

    const isZero = group.memberCount === 0;
    const isOpen = group.publicEntryAllowed === true;
    const isOwnerless = group.owner === null;

    // Filtre kontrolleri
    if (filterZero && !isZero) return null;
    if (filterOpen && !isOpen) return null;
    if (filterOwnerless && !isOwnerless) return null;

    return group;
  } catch (error) {
    // Hata durumunda (Örn: Too Many Requests - 429) yakalıyoruz
    return { error: true, message: error.message };
  }
}
async function fetchGroupData(id) {
  const filterZero = document.getElementById('filter-zero').checked;
  const filterOpen = document.getElementById('filter-open').checked;
  const filterOwnerless = document.getElementById('filter-ownerless').checked;

  try {
    // Önce doğrudan deniyoruz (Eklenti varsa çalışır)
    let response = await fetch(`https://groups.roblox.com/v1/groups/${id}` );
    
    // Eğer doğrudan erişim engellendiyse (CORS), Proxy üzerinden deniyoruz
    if (!response.ok || response.status === 0) {
        const proxyUrl = `https://api.allorigins.win/get?url=${encodeURIComponent(`https://groups.roblox.com/v1/groups/${id}` )}`;
        const proxyRes = await fetch(proxyUrl);
        const proxyData = await proxyRes.json();
        if (proxyData.contents) {
            const group = JSON.parse(proxyData.contents);
            return validateGroup(group, filterZero, filterOpen, filterOwnerless);
        }
    } else {
        const group = await response.json();
        return validateGroup(group, filterZero, filterOpen, filterOwnerless);
    }
  } catch (error) {
    return { error: true, message: "Bağlantı Sorunu" };
  }
  return null;
}

function validateGroup(group, fZero, fOpen, fOwnerless) {
    if (!group || group.errors) return null;
    const isZero = group.memberCount === 0;
    const isOpen = group.publicEntryAllowed === true;
    const isOwnerless = group.owner === null;

    if (fZero && !isZero) return null;
    if (fOpen && !isOpen) return null;
    if (fOwnerless && !isOwnerless) return null;

    return group;
}


  async function startScan() {
    const start = parseInt(document.getElementById('id-start').value) || 1;
    const end = parseInt(document.getElementById('id-end').value) || 50000;
    const maxResults = parseInt(document.getElementById('max-results').value) || 50;

    if (start >= end) { alert('Başlangıç ID\'si bitiş ID\'sinden küçük olmalı!'); return; }

    // Reset
    scanning = true;
    stopFlag = false;
    foundGroups = [];
    scanned = 0;
    errors = 0;
    currentId = start;

    document.getElementById('group-list').innerHTML = '';
    document.getElementById('log-entries').innerHTML = '';
    document.getElementById('btn-start').disabled = true;
    document.getElementById('btn-stop').disabled = false;

    startTime = Date.now();
    timerInterval = setInterval(updateTimer, 1000);
    setStatus('▶ Tarama başlatıldı...');
    addLog('Tarama başlatıldı. Aralık: ' + start + ' - ' + end, 'found');

    for (let id = start; id <= end && !stopFlag; id++) {
      currentId = id;
      scanned++;

      // Seçilen hıza göre bekle (Roblox banlamasın diye)
      await new Promise(r => setTimeout(r, scanDelay));

      // GERÇEK API'DEN VERİYİ ÇEK
      const group = await fetchGroupData(id);

      if (group) {
        
        if (group && group.error) {
    errors++;
    // Her limit aşımında bekleme süresini biraz daha artıralım
    let waitTime = 10000; // 10 saniye idealdir
    addLog(`ID #${id} — Hız Sınırı! ${waitTime/1000}sn dinleniliyor...`, 'err');
    updateStats();
    
    await new Promise(r => setTimeout(r, waitTime)); 
    id--; // Aynı ID'yi tekrar denemek için geri alıyoruz
    continue; 
}


        foundGroups.push(group);
        addGroupCard(group);
        addLog(`ID #${id} — BULUNDU: "${group.name}" (${group.memberCount} üye)`, 'found');
        setStatus(`✓ Bulundu: ${group.name}`);

        if (foundGroups.length >= maxResults) {
          addLog(`Maksimum sonuç sayısına ulaşıldı (${maxResults})`, 'err');
          stopFlag = true;
          break;
        }
      } else {
        if (document.getElementById('toggle-log').checked) {
          // addLog(`ID #${id} — Boş veya kriterlere uymuyor`, 'skip'); 
          // Not: Logları çok doldurmamak için atlananları yoruma aldım, istersen açabilirsin.
        }
      }

      updateStats();
      updateProgress();
    }

    // Done
    clearInterval(timerInterval);
    scanning = false;
    document.getElementById('btn-start').disabled = false;
    document.getElementById('btn-stop').disabled = true;

    if (stopFlag) {
      setStatus('■ Tarama durduruldu.', 'error');
    } else {
      setStatus(`✓ Tarama tamamlandı! ${foundGroups.length} grup bulundu.`, 'idle');
    }

    updateStats();
    updateProgress();
    addLog(`Tarama bitti. Toplam: ${scanned} ID, ${foundGroups.length} grup bulundu.`, 'found');

    if (foundGroups.length === 0) {
      document.getElementById('group-list').innerHTML = `
        <div class="empty-state">
          <div class="empty-icon">⬡</div>
          <div class="empty-text">SONUÇ BULUNAMADI</div>
          <div style="font-family:'Share Tech Mono',monospace;font-size:10px;color:var(--muted);margin-top:4px">Filtrelerinizi değiştirin ve tekrar deneyin</div>
        </div>`;
    }
  }

  function stopScan() {
    stopFlag = true;
    clearInterval(timerInterval);
    document.getElementById('btn-stop').disabled = true;
    setStatus('⬛ Durduruluyor...', 'error');
  }
</script>
</body>
</html>
0 yanıt0

Konuyu Yanıtla

Markdown destekler · Alıntı, kod, liste kullanabilirsiniz

Konuyu yanıtlamak için giriş yapmalısınız.

Bu konuda yer alanlar

Bu gönderinin yazarı ve yorum yazan üyeler (yalnızca bu konu).