通过 Telegram file_id 判断文件存储的数据中心

前言

最近在重写小霾的 DC Check 功能,打算把 DC2/3 加进去,而不是直接写成 DC1/4。
由于本人 Python 本当下手,一开始没看懂 Pyrogram 的源码,没搞明白他是怎么拿的 dc_id, 本来想找找 tdlib 能不能拿这个信息,结果我找了半天 tdlib 的文档,也没找到哪里有 dc 这一字段拿,随后在 tdlib 群中询问得知,tdlib 根本没把这部分暴露给用户···

不过据 tdlib 群的大佬说,通过头像判断的用户 DC 并不是真实 DC,这点暂且存疑

但是随后另一个大佬提醒,通过解码 file_id 就能判断出文件所存储的数据中心。

那么不多说,直接上代码。

参考代码

TDLib: https://github.com/tdlib/td/blob/254f10b88564b9337e77c09510a47575a08688f9/td/telegram/files/FileManager.cpp#L2923

Pyrogram: https://github.com/pyrogram/pyrogram/blob/e50b58980a68a589617f9dcfce0c52f1830b32c5/pyrogram/file_id.py#L200

通过以上逻辑可得 Node.js 参考代码:

import struct from 'python-struct'

function getDC(file_id) {
    let decoded_file_id_buf = rle_decode(Buffer.from(file_id, 'base64url'))
    const major = parseInt(decoded_file_id_buf.slice(-1).toString('hex'), 16)
    if (major < 4) {
        decoded_file_id_buf = decoded_file_id_buf.slice(0, -1)
    } else {
        decoded_file_id_buf = decoded_file_id_buf.slice(0, -2)
    }
    const [, dc] = struct.unpack('<ii', decoded_file_id_buf.slice(0, 8))
    return dc;
}

function rle_decode(bytes_buf) {
    const result = [];

    let isPreviousZero = false;
    for (const item of bytes_buf) {
        if (item === 0) {
            isPreviousZero = true;
            continue;
        }

        if (isPreviousZero) {
            result.push(...Array(item).fill(0));
            isPreviousZero = false;
        } else {
            result.push(item);
        }
    }

    return Buffer.from(result);
}

console.log(getDC('AgACAgEAAxUAAWJGy2LS9jhZRw6R2qgXlZqrRo5oAAKqpzEbUr8gNO_REKKp8zC8AQADAgADYwADIwQ'))  // DC1
console.log(getDC('AgACAgIAAxUAAWJGzJ9B4LKaPV5cjXOdO0xiQb-7AAI8uTEby3YxSvsJRGGMR2jcAQADAgADYwADIwQ'))  // DC2
console.log(getDC('AgACAgMAAxUAAWJGza3gyRKTX-Eg5BN_n0iMHpxNAAKppzEbshEJBC3NV1bsBwi3AQADAgADYwADIwQ'))  // DC3
console.log(getDC('AgACAgQAAxUAAWJGyzZFag7qs544PxHGvabVQ6wUAAIZuTEbcDIYUqVQrWEZVR2JAQADAgADYwADIwQ'))  // DC4
console.log(getDC('BQACAgUAAx0CVTVl8wACQbJiRlY8fOQVb8cEg_eiBU3A3DZ6ZwACwgYAAu5bOFaKGWHnjrb_biME'))  // DC5

PHP 参考代码:

<?php

function b64_decode(string $str): string
{
    return base64_decode(str_replace(['-', '_'], ['+', '/'], $str));
}

function rle_decode(string $bin_str): array
{
    $result = [];

    $isPreviousZero = false;
    foreach (str_split($bin_str) as $bin) {
        $dec = hexdec(bin2hex($bin));
        if ($dec === 0) {
            $isPreviousZero = true;
            continue;
        }

        if ($isPreviousZero) {
            array_push($result, ...array_fill(0, $dec, 0));
            $isPreviousZero = false;
        } else {
            $result[] = $dec;
        }
    }

    return $result;
}

function getDC(string $file_id): int
{
    $r = rle_decode(b64_decode($file_id));
    return $r[4];
}

echo getDC('AgACAgEAAxUAAWJGy2LS9jhZRw6R2qgXlZqrRo5oAAKqpzEbUr8gNO_REKKp8zC8AQADAgADYwADIwQ'), PHP_EOL;  // DC1
echo getDC('AgACAgIAAxUAAWJGzJ9B4LKaPV5cjXOdO0xiQb-7AAI8uTEby3YxSvsJRGGMR2jcAQADAgADYwADIwQ'), PHP_EOL;  // DC2
echo getDC('AgACAgMAAxUAAWJGza3gyRKTX-Eg5BN_n0iMHpxNAAKppzEbshEJBC3NV1bsBwi3AQADAgADYwADIwQ'), PHP_EOL;  // DC3
echo getDC('AgACAgQAAxUAAWJGyzZFag7qs544PxHGvabVQ6wUAAIZuTEbcDIYUqVQrWEZVR2JAQADAgADYwADIwQ'), PHP_EOL;  // DC4
echo getDC('BQACAgUAAx0CVTVl8wACQbJiRlY8fOQVb8cEg_eiBU3A3DZ6ZwACwgYAAu5bOFaKGWHnjrb_biME'), PHP_EOL;  // DC5

发表回复

您的电子邮箱地址不会被公开。