gram-js / gramjs

NodeJS/Browser MTProto API Telegram client library,
MIT License
1.3k stars 178 forks source link

Get file_id of the uploaded file #485

Open Fedya-Mercuriev opened 1 year ago

Fedya-Mercuriev commented 1 year ago

Hello everyone!

Implemented programmatic file upload mechanism using the saveBigFilePart API method. Example of a provided file id during the upload: BigInt("-4156489812597").

But as I can see, file_id that bot can access a file is quite different from what I provide. Can't access the file by the id I generated. Is there a way to get a file_id of the newly uploaded file so it can then be used by the bot? Example of the id of the file stored on telegram server: CGACAgIAAxkBAAIBpGPzcUbkesslSOD0wag7wLgOtcSxAAL2KAACWraZS0RFVFNE2ikqLgQ

painor commented 1 year ago

sadly that's a custom implementation from TDLIB. it basically stores the file_id+file_reference+file_type as a base64 string somehow.

there is no way to get that custom file_id from mtproto so you'll have to recreate it which is hard to do. It's probably easier to store the file_id,type etc you get from the messages

Fedya-Mercuriev commented 1 year ago

I wish i had the algorithm used to generate the file id for the file stored on the server which is close to impossible. Could you clarify the "It's probably easier to store the file_id,type etc you get from the messages"? How can this be implemented?

painor commented 1 year ago

well you could create a class and json parse and stringify it i guess 🤷‍♂️

Fedya-Mercuriev commented 1 year ago

well ,the thing is that i am using sendBigFilePart. This method requires the uploaded to generate random id. Tried to use it, but can't access it via this id. The actual id that one can access the file with is different and is way longer.

husone commented 1 year ago

You can create a group and a bot, send a file to the group and run a process for the bot to log message data.

const TelegramBot = require('node-telegram-bot-api');
const botToken = process.env.API_KEY;
const bot = new TelegramBot(botToken, { polling: true });
bot.on("polling_error", console.log);

bot.on('message', (msg) => {
    console.log(JSON.stringify(msg));
});
mageshyt commented 1 year ago

i also need to get the file_id 😢. have anyone found the way

Asper1x commented 1 year ago

I imported code from the 'telethon' repository to TypeScript. It only works with video and audio.

https://github.com/LonamiWebs/Telethon/blob/16ed9614f9cae7476485debdfbf67f8d7026927c/telethon/utils.py#L1226

import struct from "python-struct";
import long from "long";
import { Api } from "telegram";

export default function pack_file_id(file: Api.Document){
  const file_type = file.mimeType == "video/mp4" ? 4 : 9;

  const packed = struct.pack("<iiqqb", [file_type, file.dcId, long.fromString(file.id.toString()), long.fromString(file.accessHash.toString()), 2])
  const rle = rleEncode(packed);
  return Buffer.from(rle).toString("base64url");
}

function rleEncode(bytes: Uint8Array): Uint8Array {
  let newBytes: Uint8Array = new Uint8Array();
  let count: number = 0;

  for (const cur of bytes) {
    if (!cur) {
      count += 1;
    } else {
      if (count) {
        newBytes = concatenateUint8Arrays(newBytes, new Uint8Array([0, count]));
        count = 0;
      }

      newBytes = concatenateUint8Arrays(newBytes, new Uint8Array([cur]));
    }
  }

  return newBytes;
}

function concatenateUint8Arrays(a: Uint8Array, b: Uint8Array): Uint8Array {
  const result = new Uint8Array(a.length + b.length);
  result.set(a);
  result.set(b, a.length);
  return result;
}