mtproto-core icon indicating copy to clipboard operation
mtproto-core copied to clipboard

API messages.sendMultiMedia Always Fails (400 MEDIA_INVALID) for valid media

Open mvdicarlo opened this issue 4 years ago • 10 comments

I have been trying to get this particular api method to work (https://core.telegram.org/method/messages.sendMultiMedia).

I have provided sample code below that I am using to test this behavior. It shouldn't be an issue of the actual file being invalid as if you attempt to send the media using https://core.telegram.org/method/messages.sendMedia it works just fine.

It appears to be a bug, but I don't know enough about the protocol implementation to be able to fix it myself.

const { MTProto } = require("@mtproto/core");
const readline = require("readline");
const fs = require("fs");

const api_id = "<app id>";
const api_hash = "<app hash>";
const phone_number = "<phone>";
const file = fs.readFileSync("test.jpg"); // assumes under 512kb

// 1. Create an instance
const mtproto = new MTProto({
  api_id,
  api_hash,
});

async function auth() {
  const send = await mtproto.call("auth.sendCode", {
    phone_number,
    settings: {
      _: "codeSettings",
    },
  });

  const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
  });

  const code = await new Promise((resolve) => {
    rl.question("Code: ", (answer) => {
      rl.close();
      resolve(answer);
    });
  });

  const authed = await mtproto.call("auth.signIn", {
    phone_code: code,
    phone_number,
    phone_code_hash: send.phone_code_hash,
  });

  console.log(authed);
}

async function getChats() {
  return await mtproto
    .call("messages.getAllChats", {
      except_ids: [],
    })
    .then(({ chats }) => chats);
}

function wait() {
  return new Promise((resolve) => {
    setTimeout(resolve, 2000);
  });
}

async function upload(file) {
  const id = Date.now();
  await mtproto.call("upload.saveFilePart", {
    file_id: id,
    file_part: 0,
    bytes: file,
  });
  return id;
}

// This does all the stuff
async function run() {
  mtproto.setDefaultDc(
    await mtproto.call("help.getNearestDc").then((result) => {
      return result.nearest_dc;
    })
  );

  let chats;
  try {
    chats = await getChats();
  } catch {
    await auth();
    chats = await getChats();
  }

  const chat = chats[0];
  await wait();
  const upl = await upload(file);
  await wait();

// I AM BROKEN
  const res = await mtproto
    .call("messages.sendMultiMedia", {
      peer: {
        _: "inputPeerChannel",
        channel_id: chat.id,
        access_hash: chat.access_hash,
      },
      multi_media: [
        {
          _: "inputSingleMedia",
          random_id: Date.now(),
          //   message: "Hello, World!",
          media: {
            _: "inputMediaUploadedPhoto",
            file: {
              _: "inputFile",
              id: upl,
              name: "test.jpg",
              parts: 1,
            },
          },
        },
      ],
    })
    .catch((err) => err);
  // UNCOMMENT ME TO SEE THAT messages.sendMedia works correctly.
  //   const res = await mtproto
  //     .call("messages.sendMedia", {
  //       random_id: Date.now(),
  //       peer: {
  //         _: "inputPeerChannel",
  //         channel_id: chat.id,
  //         access_hash: chat.access_hash,
  //       },
  //       message: "Hello, World",
  //       media: {
  //         _: "inputMediaUploadedPhoto",
  //         file: {
  //           _: "inputFile",
  //           id: upl,
  //           name: "test.jpg",
  //           parts: 1,
  //         },
  //       },
  //     })
  //     .catch((err) => err);

  console.log(res);
}

run()
  .catch(console.error)
  .finally(() => process.exit(0));

process.on("unhandledRejection", console.error);

mvdicarlo avatar Jan 22 '21 20:01 mvdicarlo

https://stackoverflow.com/questions/65628877/in-nodejs-telegram-api-messages-sendmultimedia-method-is-not-working

meylisatamuradov avatar Jan 27 '21 10:01 meylisatamuradov

I have the same question. Have you solved your problem

bigbigsir avatar Apr 18 '21 17:04 bigbigsir

@alik0211

bigbigsir avatar Apr 18 '21 17:04 bigbigsir

@mvdicarlo Have you solved your problem? I need help

ember999 avatar May 18 '21 12:05 ember999

No. I just accepted the less preferable way of sending individually for now. Wasn't able to tell if this was a limitation of the library or some limitation of the Telegram API.

I don't know enough about the protocol to debug it myself

mvdicarlo avatar May 18 '21 12:05 mvdicarlo

I tried everything,This is very frustrating,The author doesn't have any explanation

2021年5月18日 下午8:34,Lemonynade @.***> 写道:

No. I just accepted the less preferable way of sending individually for now. Wasn't able to tell if this was a limitation of the library or some limitation of the Telegram API.

I don't know enough about the protocol to debug it myself

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/alik0211/mtproto-core/issues/148#issuecomment-843132377, or unsubscribe https://github.com/notifications/unsubscribe-auth/ARDPXOTYCPI5TUMXMWXJMELTOJNDXANCNFSM4WPAAHKA.

ember999 avatar May 18 '21 12:05 ember999

Any update on this issue? I try all kinds of ways but still the response is "400 MEDIA_INVALID"

milad7290 avatar Feb 13 '22 11:02 milad7290

This is just fuck this is so stupid, why python has everything while js developers has to deal with dead library with "call" method that pretty much don't do anything, what the actual fuck why just why

VityaSchel avatar Jul 03 '22 18:07 VityaSchel

I'm going to try to patch this error. It seems that problem is at src/tl/builder/index.js:7159

'messages.sendMultiMedia': function(params) {
    this.int32(-134016113);
    const flags = (this.has(params.silent) << 5) | (this.has(params.background) << 6) | (this.has(params.clear_draft) << 7) | (this.has(params.noforwards) << 14) | (this.has(params.reply_to_msg_id) << 0) | (this.has(params.schedule_date) << 10) | (this.has(params.send_as) << 13);
    this.int32(flags);
    this.predicate(params.peer);
    this.flag(this.int, params.reply_to_msg_id);
    this.vector(this.predicate, params.multi_media);
    this.flag(this.int, params.schedule_date);
    this.flag(this.predicate, params.send_as);
  },

VityaSchel avatar Jul 03 '22 18:07 VityaSchel

you may use uploadMedia to upload each photo

...
...
// step 1 ,upload the file
const chat = chats[0];
await wait();
const upl_id = await upload(file);
await wait();
// step2, uploadMedia
const upl_media = await mtproto('messages.uploadMedia', {
    peer: target_peer,
    media: {
        "_": "inputMediaUploadedPhoto",
        "file": {
            "_": "inputFile",
            "id": upl_id,
            "parts": 1,
            "name": 'upload.png',
            "md5_checksum": ""
        },
        "mime_type": "image/png",
        "attributes": [{
            "_": "documentAttributeFilename",
            "file_name": 'upload.png'
        }]
    }
})
// step 3 send multi media
const res = await mtproto
    .call("messages.sendMultiMedia", {
        peer: {
            _: "inputPeerChannel",
            channel_id: chat.id,
            access_hash: chat.access_hash,
        },
        multi_media: [{
            "_": "inputSingleMedia",
            "random_id": this.createSendMessageId(),
            "message": text,
            "entities": entities,
            "media": {
                "_": "inputMediaPhoto",
                "id": {
                    "_": 'inputPhoto',
                    "id": upl_media.photo.id,
                    "access_hash": upl_media.photo.access_hash,
                    "file_reference": upl_media.photo.file_reference
                }
            }
        }, {
            "_": "inputSingleMedia",
            "random_id": this.createSendMessageId(),
            "media": {
                "_": "inputMediaPhoto",
                "id": {
                    "_": 'inputPhoto',
                    "id": upl_media.photo.id,
                    "access_hash": upl_media.photo.access_hash,
                    "file_reference": upl_media.photo.file_reference
                }
            }
        }],
    })
    .catch((err) => err);

=========================================================================================== the code is work for me.

ghost avatar Sep 11 '22 02:09 ghost