Full Code of metowolf/qqwry.dat for AI

main 83ff6a8a0a13 cached
8 files
22.1 KB
7.7k tokens
8 symbols
1 requests
Download .txt
Repository: metowolf/qqwry.dat
Branch: main
Commit: 83ff6a8a0a13
Files: 8
Total size: 22.1 KB

Directory structure:
gitextract_ujgryagc/

├── .github/
│   └── workflows/
│       └── release.yml
├── .gitignore
├── README.md
├── package.json
├── protocol.md
├── src/
│   ├── build.js
│   └── packer.js
└── version.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/workflows/release.yml
================================================
name: Release

on:
  workflow_dispatch:
  schedule:
    - cron: '15 8,20 * * *'

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: pnpm/action-setup@v4
        with:
          version: 9
      - name: Checkout
        uses: actions/checkout@v3
      - name: Build
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          DOWNLOAD_TOKEN: ${{ secrets.DOWNLOAD_TOKEN }}
          CZDB_TOKEN: ${{ secrets.CZDB_TOKEN }}
        run: |
          pnpm i
          pnpm run build


================================================
FILE: .gitignore
================================================
dist/
node_modules/
temp/

================================================
FILE: README.md
================================================
纯真 IP 数据库自动同步仓库

# 使用说明

下载最新版本
```
wget https://github.com/metowolf/qqwry.dat/releases/latest/download/qqwry.dat
```

获取最新版本号 YYYYMMDD 格式
```
curl https://raw.githubusercontent.com/metowolf/qqwry.dat/main/version.json | jq -r .latest
```


================================================
FILE: package.json
================================================
{
  "name": "qqwry.dat",
  "version": "1.0.0",
  "type": "module",
  "repository": "git@github.com:metowolf/qqwry.dat.git",
  "author": "metowolf <i@i-meto.com>",
  "license": "MIT",
  "scripts": {
    "build": "node src/build.js"
  },
  "devDependencies": {
    "@ipdb/czdb": "^0.0.2",
    "execa": "^9.5.2",
    "iconv-lite": "^0.6.3",
    "lib-qqwry": "^1.3.4"
  }
}


================================================
FILE: protocol.md
================================================
# File Structure

All integers are stored in little-endian format.

```
┌─────────────────────────────────┐
│           File Header           │ 8 bytes
├─────────────────────────────────┤
│          Record Zone            │ Variable length
├─────────────────────────────────┤
│           Index Zone            │ 7 bytes × n entries
└─────────────────────────────────┘
```

## File Header Detail

```
┌───────────────┬───────────────┐
│ First Index   │  Last Index   │
│   Offset      │    Offset     │
│   4 bytes     │    4 bytes    │
└───────────────┴───────────────┘
```

## Record Zone Entry Detail

All strings are GBK encoded and null-terminated.

```
┌──────────┬───────────┬──────────┐
│  End IP  │  Country  │   Area   │
│ 4 bytes  │ Variable  │ Variable │
└──────────┴───────────┴──────────┘

A. Direct String:
┌─────────────┬───┐
│   String    │ 0 │ 
└─────────────┴───┘

B. Redirect Mode 1 (0x01):
┌────┬───────────┐
│ 01 │  Offset   │ → Points to [Country][Area]
└────┴───────────┘
     3 bytes

C. Redirect Mode 2 (0x02):
┌────┬───────────┐
│ 02 │  Offset   │
└────┴───────────┘
     3 bytes
```

## Index Zone Entry Detail

```
┌──────────────┬─────────────┐
│   Start IP   │   Offset    │
│   4 bytes    │   3 bytes   │
└──────────────┴─────────────┘
                 Points to Record Zone
```

## Link

- https://web.archive.org/web/20140423114336/http://lumaqq.linuxsir.org/article/qqwry_format_detail.html

================================================
FILE: src/build.js
================================================
import fs from 'fs'
import { execa } from 'execa'
import libqqwry from 'lib-qqwry'
import Decoder from '@ipdb/czdb'
import QQWryPacker from './packer.js'

const DOWNLOAD_TOKEN = process.env.DOWNLOAD_TOKEN
const CZDB_TOKEN = process.env.CZDB_TOKEN

const download = async () => {
  const url = `https://www.cz88.net/api/communityIpAuthorization/communityIpDbFile?fn=czdb&key=${DOWNLOAD_TOKEN}`
  await fs.promises.mkdir('./temp', { recursive: true })
  await execa('wget', ['--timeout=30', '--tries=3', '-O', './temp/download.zip', url])
  // 解压
  await execa('unzip', ['./temp/download.zip', '-d', './temp'])
}

const extract = async () => {
  const qqwryPacker = new QQWryPacker()
  const decoder = new Decoder('./temp/cz88_public_v4.czdb', CZDB_TOKEN)
  decoder.dump(info => {
    const { startIp, endIp, regionInfo } = info
    // 过滤 IPv6
    if (startIp.includes(':')) {
      return
    }
    // 分离 geo, isp
    const [geo, isp] = regionInfo.split('\t', 2)
    // 生成记录
    qqwryPacker.insert(startIp, endIp, geo, isp)
  })

  // 生成二进制文件
  const buffer = qqwryPacker.build()
  await fs.promises.mkdir('./dist', { recursive: true })
  fs.writeFileSync('./dist/qqwry.dat', buffer)
}

const parseQQwryInfo = async () => {
  const qqwry = libqqwry(true, './dist/qqwry.dat')

  const info = {
    count: 0,
    unique: 0,
  }
  
  const unique = new Set()

  let ip = '0.0.0.0'
  while (true) {
    let data = qqwry.searchIPScope(ip, ip)[0]
    // stat
    info.count += 1
    const hashkey = `${data.Country}${data.Area}`
    if (!unique.has(hashkey)) {
      info.unique += 1
      unique.add(hashkey)
    }
    if (data.endIP === '255.255.255.255') break
    ip = libqqwry.intToIP(data.endInt + 1)
  }

  return info
}

const readInfo = () => {
  const data = fs.readFileSync('./version.json', 'utf-8')
  return JSON.parse(data)
}

const parseQQWryVersion = () => {
  const qqwry = libqqwry(true, './dist/qqwry.dat')
  const info = qqwry.searchIP('255.255.255.255')
  return info.Area.match(/(\d+)/gi).join('')
}

const release = async () => {
  const info = await readInfo()
  const currentVersion = parseQQWryVersion()
  if (info.latest === currentVersion || info.versions[currentVersion]) {
    console.log('No new version, skip')
    return
  }

  const currentInfo = await parseQQwryInfo()

  if (!info.versions[currentVersion]) {
    info.versions[currentVersion] = currentInfo
    if (info.latest < currentVersion) {
      info.latest = currentVersion
    }
    fs.writeFileSync('./version.json', JSON.stringify(info, null, 2))

    console.log({
      info,
      currentVersion,
      currentInfo
    })

    await execa('gh', ['release', 'create', currentVersion, '-t', currentVersion, '-n', `QQWry version: ${currentVersion}`, './dist/qqwry.dat'])
    await execa('git', ['config', 'user.name', 'github-actions'])
    await execa('git', ['config', 'user.email', 'i@i-meto.com'])
    await execa('git', ['add', './version.json'])
    await execa('git', ['commit', '-m', `chore: update version info to ${currentVersion}`])
    await execa('git', ['push'])
  }

}

const main = async () => {
  // 0. 下载 czdb 并解压
  await download()
  console.log('Downloaded')

  // 1. 反解压 czdb 并生成 qqwry.dat
  await extract()
  console.log('Extracted')

  // 2. 生成版本信息
  await release()
  console.log('Released')
}

main()

================================================
FILE: src/packer.js
================================================
import iconv from 'iconv-lite'

class QQWryPacker {
  constructor() {
    this.indexList = []      // IP索引区
    this.recordList = []     // 记录区
    this.ipTree = new Map()  // IP树
    this.stringCache = new Map() // 字符串缓存
    this.maxRecordOffset = 8
  }

  // 插入一条IP记录
  insert(startIP, endIP, country, area) {
    const startIPInt = this._ipToInt(startIP)
    const endIPInt = this._ipToInt(endIP)
    const geoOffset = this.maxRecordOffset
    this._createRecord(endIPInt, country, area || 'CZ88.NET')
    this.ipTree.set(startIPInt, { endIPInt, geoOffset, country, area: area || 'CZ88.NET' })
  }

  // 生成最终的二进制文件
  build() {
    // 1. 构造数据区
    const recordBuffer = Buffer.concat(this.recordList)

    // 2. 构造索引区
    const sortedIPs = Array.from(this.ipTree.keys()).sort((a, b) => a - b)
    const indexList = []

    for (let i = 0; i < sortedIPs.length; i++) {
      const startIPInt = sortedIPs[i]
      const { geoOffset } = this.ipTree.get(startIPInt)
      const indexRecord = Buffer.alloc(7)
      indexRecord.writeUInt32LE(startIPInt, 0)
      if (geoOffset > 0xFFFFFF) {
        throw new Error('Offset overflow')
      }
      indexRecord.writeUInt8((geoOffset >> 0) & 0xFF, 4)
      indexRecord.writeUInt8((geoOffset >> 8) & 0xFF, 5)
      indexRecord.writeUInt8((geoOffset >> 16) & 0xFF, 6)
      indexList.push(indexRecord)
    }

    // 3. 构造文件头
    const headerBuffer = Buffer.alloc(8)
    headerBuffer.writeUInt32LE(8 + recordBuffer.length, 0)
    headerBuffer.writeUInt32LE(8 + recordBuffer.length + sortedIPs.length * 7 - 7, 4)

    console.log([
      '文件头长度:', headerBuffer.length,
      '记录区长度:', recordBuffer.length,
      '索引区长度:', Buffer.concat(indexList).length,
      '记录数:', sortedIPs.length,
    ])

    // 4. 合并所有部分
    return Buffer.concat([
      headerBuffer,  // 文件头
      recordBuffer,  // 记录区
      ...indexList // 索引区
    ])
  }

  _ipToInt(ip) {
    const parts = ip.split('.')
    // 使用无符号右移确保结果为正数
    return ((parseInt(parts[0]) << 24) |
      (parseInt(parts[1]) << 16) |
      (parseInt(parts[2]) << 8) |
      parseInt(parts[3])) >>> 0
  }

  _createRecord(endIPInt, country, area) {
    // 写入 endIP
    const recordBuf = Buffer.alloc(4)
    recordBuf.writeUInt32LE(endIPInt, 0)
    this.recordList.push(recordBuf)
    this.maxRecordOffset += 4

    // country + area 都有的记录
    if (this.stringCache.has(`${country}\t${area}`)) {
      const redirectBuf = Buffer.alloc(4)
      redirectBuf.writeUInt8(0x01, 0)
      const offset = this.stringCache.get(`${country}\t${area}`)
      redirectBuf.writeUInt8((offset >> 0) & 0xFF, 1)
      redirectBuf.writeUInt8((offset >> 8) & 0xFF, 2)
      redirectBuf.writeUInt8((offset >> 16) & 0xFF, 3)
      this.recordList.push(redirectBuf)
      this.maxRecordOffset += 4
      return
    }

    // country, area 分开都有的记录
    if (this.stringCache.has(country) && this.stringCache.has(area)) {
      const countryOffset = this.stringCache.get(country)
      const areaOffset = this.stringCache.get(area)

      // 生成缓存键:基于两个偏移的组合
      const ptrCacheKey = `ptr:${countryOffset}:${areaOffset}`

      // 检查是否已有相同的指针组合
      if (this.stringCache.has(ptrCacheKey)) {
        // 复用:用 0x01 重定向到已有的 8 字节块
        const existingOffset = this.stringCache.get(ptrCacheKey)
        const redirectBuf = Buffer.alloc(4)
        redirectBuf.writeUInt8(0x01, 0)
        redirectBuf.writeUInt8((existingOffset >> 0) & 0xFF, 1)
        redirectBuf.writeUInt8((existingOffset >> 8) & 0xFF, 2)
        redirectBuf.writeUInt8((existingOffset >> 16) & 0xFF, 3)
        this.recordList.push(redirectBuf)
        this.maxRecordOffset += 4
        return
      }

      // 首次出现:直接写入 8 字节(省略 0x01 层)
      const currentOffset = this.maxRecordOffset

      const countryBuf = Buffer.alloc(4)
      countryBuf.writeUInt8(0x02, 0)
      countryBuf.writeUInt8((countryOffset >> 0) & 0xFF, 1)
      countryBuf.writeUInt8((countryOffset >> 8) & 0xFF, 2)
      countryBuf.writeUInt8((countryOffset >> 16) & 0xFF, 3)

      const areaBuf = Buffer.alloc(4)
      areaBuf.writeUInt8(0x02, 0)
      areaBuf.writeUInt8((areaOffset >> 0) & 0xFF, 1)
      areaBuf.writeUInt8((areaOffset >> 8) & 0xFF, 2)
      areaBuf.writeUInt8((areaOffset >> 16) & 0xFF, 3)

      this.recordList.push(countryBuf)
      this.recordList.push(areaBuf)
      this.maxRecordOffset += 8

      // 缓存这个 8 字节块的位置
      this.stringCache.set(ptrCacheKey, currentOffset)
      // 保持原有的组合缓存(用于策略 1)
      this.stringCache.set(`${country}\t${area}`, currentOffset)
      return
    }

    // country 有 area 没有的记录
    if (this.stringCache.has(country)) {
      const currentOffset = this.maxRecordOffset
      const countryOffset = this.stringCache.get(country)
      const countryBuf = Buffer.alloc(4)
      countryBuf.writeUInt8(0x02, 0)
      countryBuf.writeUInt8((countryOffset >> 0) & 0xFF, 1)
      countryBuf.writeUInt8((countryOffset >> 8) & 0xFF, 2)
      countryBuf.writeUInt8((countryOffset >> 16) & 0xFF, 3)

      const areaBuf = Buffer.concat([
        iconv.encode(area || '', 'gbk'),
        Buffer.from([0x00])
      ])

      this.recordList.push(countryBuf)
      this.recordList.push(areaBuf)
      this.maxRecordOffset += countryBuf.length + areaBuf.length

      // 缓存
      const areaOffset = currentOffset + countryBuf.length
      this.stringCache.set(area, areaOffset)
      this.stringCache.set(`${country}\t${area}`, currentOffset)
      return
    }

    // 其他情况
    const currentOffset = this.maxRecordOffset
    const countryBuf = Buffer.concat([
      iconv.encode(country || '', 'gbk'),
      Buffer.from([0x00])
    ])
    const areaBuf = Buffer.concat([
      iconv.encode(area || '', 'gbk'),
      Buffer.from([0x00])
    ])

    this.recordList.push(countryBuf)
    this.recordList.push(areaBuf)
    this.maxRecordOffset += countryBuf.length + areaBuf.length

    // 缓存
    const areaOffset = currentOffset + countryBuf.length
    this.stringCache.set(`${country}`, currentOffset)
    this.stringCache.set(area, areaOffset)
    this.stringCache.set(`${country}\t${area}`, currentOffset)
  }
}

export default QQWryPacker

================================================
FILE: version.json
================================================
{
  "latest": "20260415",
  "versions": {
    "20221005": {
      "count": 530599,
      "unique": 156555
    },
    "20221012": {
      "count": 530606,
      "unique": 156559
    },
    "20221019": {
      "count": 530598,
      "unique": 156557
    },
    "20221026": {
      "count": 530613,
      "unique": 156558
    },
    "20221102": {
      "count": 530632,
      "unique": 156559
    },
    "20221109": {
      "count": 530283,
      "unique": 156534
    },
    "20221116": {
      "count": 530310,
      "unique": 156530
    },
    "20221123": {
      "count": 530387,
      "unique": 156538
    },
    "20221207": {
      "count": 530416,
      "unique": 156532
    },
    "20221214": {
      "count": 530424,
      "unique": 156532
    },
    "20221221": {
      "count": 530422,
      "unique": 156532
    },
    "20221228": {
      "count": 530429,
      "unique": 156599
    },
    "20230104": {
      "count": 530432,
      "unique": 156599
    },
    "20230111": {
      "count": 530438,
      "unique": 156601
    },
    "20230118": {
      "count": 530452,
      "unique": 156603
    },
    "20230125": {
      "count": 530460,
      "unique": 156606
    },
    "20230201": {
      "count": 530475,
      "unique": 156608
    },
    "20230208": {
      "count": 530501,
      "unique": 156610
    },
    "20230215": {
      "count": 530548,
      "unique": 156615
    },
    "20230222": {
      "count": 530586,
      "unique": 156623
    },
    "20230301": {
      "count": 530599,
      "unique": 156664
    },
    "20230308": {
      "count": 530600,
      "unique": 156725
    },
    "20230315": {
      "count": 530585,
      "unique": 157012
    },
    "20230322": {
      "count": 530523,
      "unique": 160559
    },
    "20230405": {
      "count": 530571,
      "unique": 162291
    },
    "20230419": {
      "count": 530638,
      "unique": 161940
    },
    "20230426": {
      "count": 530697,
      "unique": 161953
    },
    "20230510": {
      "count": 530805,
      "unique": 161980
    },
    "20230517": {
      "count": 530831,
      "unique": 161989
    },
    "20230524": {
      "count": 530870,
      "unique": 162003
    },
    "20230607": {
      "count": 530889,
      "unique": 162009
    },
    "20230614": {
      "count": 531340,
      "unique": 162133
    },
    "20230621": {
      "count": 531380,
      "unique": 162138
    },
    "20230628": {
      "count": 531400,
      "unique": 162144
    },
    "20230705": {
      "count": 531635,
      "unique": 162206
    },
    "20230726": {
      "count": 545203,
      "unique": 162299
    },
    "20230802": {
      "count": 545277,
      "unique": 162316
    },
    "20230809": {
      "count": 545361,
      "unique": 162343
    },
    "20230823": {
      "count": 545617,
      "unique": 162419
    },
    "20230913": {
      "count": 546118,
      "unique": 162597
    },
    "20230920": {
      "count": 546212,
      "unique": 162606
    },
    "20230927": {
      "count": 546633,
      "unique": 162627
    },
    "20231011": {
      "count": 546712,
      "unique": 162648
    },
    "20231018": {
      "count": 546739,
      "unique": 162655
    },
    "20231025": {
      "count": 546956,
      "unique": 162667
    },
    "20231108": {
      "count": 547183,
      "unique": 162691
    },
    "20231115": {
      "count": 547242,
      "unique": 162691
    },
    "20231122": {
      "count": 547299,
      "unique": 162704
    },
    "20231213": {
      "count": 547514,
      "unique": 162726
    },
    "20231220": {
      "count": 547557,
      "unique": 162729
    },
    "20231227": {
      "count": 547635,
      "unique": 162740
    },
    "20240103": {
      "count": 547639,
      "unique": 162740
    },
    "20240110": {
      "count": 547681,
      "unique": 162741
    },
    "20240117": {
      "count": 547698,
      "unique": 162742
    },
    "20240124": {
      "count": 547722,
      "unique": 162745
    },
    "20240131": {
      "count": 547744,
      "unique": 162750
    },
    "20240207": {
      "count": 547753,
      "unique": 162751
    },
    "20240214": {
      "count": 547760,
      "unique": 162751
    },
    "20240221": {
      "count": 547783,
      "unique": 162765
    },
    "20240228": {
      "count": 547947,
      "unique": 162769
    },
    "20240306": {
      "count": 547750,
      "unique": 162753
    },
    "20240313": {
      "count": 547762,
      "unique": 162754
    },
    "20240320": {
      "count": 547857,
      "unique": 162753
    },
    "20240327": {
      "count": 548329,
      "unique": 162823
    },
    "20240403": {
      "count": 578950,
      "unique": 163491
    },
    "20240410": {
      "count": 591425,
      "unique": 164525
    },
    "20240417": {
      "count": 599415,
      "unique": 165770
    },
    "20240424": {
      "count": 600034,
      "unique": 165952
    },
    "20240508": {
      "count": 628031,
      "unique": 166831
    },
    "20240515": {
      "count": 1221918,
      "unique": 167456
    },
    "20240522": {
      "count": 1465151,
      "unique": 167531
    },
    "20240529": {
      "count": 1465430,
      "unique": 167550
    },
    "20240605": {
      "count": 1465577,
      "unique": 167562
    },
    "20240612": {
      "count": 1465857,
      "unique": 167598
    },
    "20240619": {
      "count": 1465450,
      "unique": 166536
    },
    "20240626": {
      "count": 1463756,
      "unique": 166554
    },
    "20240703": {
      "count": 1463859,
      "unique": 166564
    },
    "20240710": {
      "count": 1463934,
      "unique": 166579
    },
    "20240911": {
      "count": 1470296,
      "unique": 167555
    },
    "20240925": {
      "count": 1491882,
      "unique": 170650
    },
    "20241225": {
      "count": 1497246,
      "unique": 171027
    },
    "20250101": {
      "count": 1497606,
      "unique": 171048
    },
    "20250108": {
      "count": 1499133,
      "unique": 171292
    },
    "20250115": {
      "count": 1499426,
      "unique": 171320
    },
    "20250122": {
      "count": 1499518,
      "unique": 171336
    },
    "20250129": {
      "count": 1500053,
      "unique": 171366
    },
    "20250205": {
      "count": 1500234,
      "unique": 171374
    },
    "20250212": {
      "count": 1500678,
      "unique": 171382
    },
    "20250219": {
      "count": 1502228,
      "unique": 171565
    },
    "20250226": {
      "count": 1502538,
      "unique": 171589
    },
    "20250305": {
      "count": 1502784,
      "unique": 171597
    },
    "20250312": {
      "count": 1503240,
      "unique": 171602
    },
    "20250319": {
      "count": 1503712,
      "unique": 171606
    },
    "20250326": {
      "count": 1503908,
      "unique": 171605
    },
    "20250402": {
      "count": 1504242,
      "unique": 171610
    },
    "20250409": {
      "count": 1504441,
      "unique": 171615
    },
    "20250416": {
      "count": 1504873,
      "unique": 171623
    },
    "20250423": {
      "count": 1505280,
      "unique": 171645
    },
    "20250430": {
      "count": 1505524,
      "unique": 171641
    },
    "20250507": {
      "count": 1505651,
      "unique": 171643
    },
    "20250514": {
      "count": 1505876,
      "unique": 171645
    },
    "20250521": {
      "count": 1506135,
      "unique": 171649
    },
    "20250528": {
      "count": 1506279,
      "unique": 171671
    },
    "20250604": {
      "count": 1506465,
      "unique": 171669
    },
    "20250611": {
      "count": 1506669,
      "unique": 171676
    },
    "20250618": {
      "count": 1507011,
      "unique": 171683
    },
    "20250625": {
      "count": 1507345,
      "unique": 171691
    },
    "20250702": {
      "count": 1508023,
      "unique": 171761
    },
    "20250709": {
      "count": 1508640,
      "unique": 171846
    },
    "20250716": {
      "count": 1509472,
      "unique": 171917
    },
    "20250723": {
      "count": 1510061,
      "unique": 171957
    },
    "20250730": {
      "count": 1510563,
      "unique": 172002
    },
    "20250806": {
      "count": 1511161,
      "unique": 172012
    },
    "20250813": {
      "count": 1512917,
      "unique": 172032
    },
    "20250820": {
      "count": 1513246,
      "unique": 172048
    },
    "20250827": {
      "count": 1513404,
      "unique": 172057
    },
    "20250903": {
      "count": 1513733,
      "unique": 172065
    },
    "20250910": {
      "count": 1513841,
      "unique": 172066
    },
    "20250917": {
      "count": 1513968,
      "unique": 172076
    },
    "20250924": {
      "count": 1514285,
      "unique": 172085
    },
    "20251001": {
      "count": 1514499,
      "unique": 172073
    },
    "20251008": {
      "count": 1514536,
      "unique": 172079
    },
    "20251015": {
      "count": 1514763,
      "unique": 172094
    },
    "20251022": {
      "count": 1514904,
      "unique": 172096
    },
    "20251029": {
      "count": 1515943,
      "unique": 172092
    },
    "20251105": {
      "count": 1516117,
      "unique": 172097
    },
    "20251112": {
      "count": 1516398,
      "unique": 172108
    },
    "20251119": {
      "count": 1516499,
      "unique": 172126
    },
    "20251126": {
      "count": 1516582,
      "unique": 172112
    },
    "20251203": {
      "count": 1516869,
      "unique": 172114
    },
    "20251210": {
      "count": 1516927,
      "unique": 172129
    },
    "20251217": {
      "count": 1517124,
      "unique": 172130
    },
    "20251224": {
      "count": 1517155,
      "unique": 172098
    },
    "20251231": {
      "count": 1516654,
      "unique": 172067
    },
    "20260107": {
      "count": 1516779,
      "unique": 172069
    },
    "20260114": {
      "count": 1516888,
      "unique": 172079
    },
    "20260121": {
      "count": 1516987,
      "unique": 172093
    },
    "20260128": {
      "count": 1517149,
      "unique": 172075
    },
    "20260204": {
      "count": 1517652,
      "unique": 172078
    },
    "20260211": {
      "count": 1517758,
      "unique": 172085
    },
    "20260218": {
      "count": 1518892,
      "unique": 172108
    },
    "20260225": {
      "count": 1518990,
      "unique": 172121
    },
    "20260304": {
      "count": 1519155,
      "unique": 172139
    },
    "20260311": {
      "count": 1519910,
      "unique": 172153
    },
    "20260318": {
      "count": 1520032,
      "unique": 172165
    },
    "20260325": {
      "count": 1521275,
      "unique": 172372
    },
    "20260401": {
      "count": 1521384,
      "unique": 172383
    },
    "20260408": {
      "count": 1521597,
      "unique": 172401
    },
    "20260415": {
      "count": 1522039,
      "unique": 172421
    }
  }
}
Download .txt
gitextract_ujgryagc/

├── .github/
│   └── workflows/
│       └── release.yml
├── .gitignore
├── README.md
├── package.json
├── protocol.md
├── src/
│   ├── build.js
│   └── packer.js
└── version.json
Download .txt
SYMBOL INDEX (8 symbols across 2 files)

FILE: src/build.js
  constant DOWNLOAD_TOKEN (line 7) | const DOWNLOAD_TOKEN = process.env.DOWNLOAD_TOKEN
  constant CZDB_TOKEN (line 8) | const CZDB_TOKEN = process.env.CZDB_TOKEN

FILE: src/packer.js
  class QQWryPacker (line 3) | class QQWryPacker {
    method constructor (line 4) | constructor() {
    method insert (line 13) | insert(startIP, endIP, country, area) {
    method build (line 22) | build() {
    method _ipToInt (line 64) | _ipToInt(ip) {
    method _createRecord (line 73) | _createRecord(endIPInt, country, area) {
Condensed preview — 8 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (26K chars).
[
  {
    "path": ".github/workflows/release.yml",
    "chars": 507,
    "preview": "name: Release\n\non:\n  workflow_dispatch:\n  schedule:\n    - cron: '15 8,20 * * *'\n\njobs:\n  build:\n    runs-on: ubuntu-late"
  },
  {
    "path": ".gitignore",
    "chars": 25,
    "preview": "dist/\nnode_modules/\ntemp/"
  },
  {
    "path": "README.md",
    "chars": 239,
    "preview": "纯真 IP 数据库自动同步仓库\n\n# 使用说明\n\n下载最新版本\n```\nwget https://github.com/metowolf/qqwry.dat/releases/latest/download/qqwry.dat\n```\n\n获"
  },
  {
    "path": "package.json",
    "chars": 370,
    "preview": "{\n  \"name\": \"qqwry.dat\",\n  \"version\": \"1.0.0\",\n  \"type\": \"module\",\n  \"repository\": \"git@github.com:metowolf/qqwry.dat.gi"
  },
  {
    "path": "protocol.md",
    "chars": 1424,
    "preview": "# File Structure\n\nAll integers are stored in little-endian format.\n\n```\n┌─────────────────────────────────┐\n│           "
  },
  {
    "path": "src/build.js",
    "chars": 3315,
    "preview": "import fs from 'fs'\nimport { execa } from 'execa'\nimport libqqwry from 'lib-qqwry'\nimport Decoder from '@ipdb/czdb'\nimpo"
  },
  {
    "path": "src/packer.js",
    "chars": 6076,
    "preview": "import iconv from 'iconv-lite'\n\nclass QQWryPacker {\n  constructor() {\n    this.indexList = []      // IP索引区\n    this.rec"
  },
  {
    "path": "version.json",
    "chars": 10705,
    "preview": "{\n  \"latest\": \"20260415\",\n  \"versions\": {\n    \"20221005\": {\n      \"count\": 530599,\n      \"unique\": 156555\n    },\n    \"20"
  }
]

About this extraction

This page contains the full source code of the metowolf/qqwry.dat GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 8 files (22.1 KB), approximately 7.7k tokens, and a symbol index with 8 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!