0

I want to stream and download file using aiohttp. Chrome can support the resume capability of download link But the download manager cannot download the file with the resume capability.

In the code below I used aiohttp framework to stream and download the file, I've also set the header parameter ('Accept-Ranges') to support resume capability.

from telethon import TelegramClient, events
client = TelegramClient(name, api_id,api_hash)

@routes.get('/{userid}/{msgid}')
async def handle(request):
    ...
    response = web.StreamResponse(
        status=200,
        reason='OK',
        headers={
            'Content-Type': content_type,
            'Content-Length':str(file_size),
            'Accept-Ranges': 'bytes',
            'Connection': 'keep-alive',
        }
    )
    await response.prepare(request)
    async for chunk in client.iter_download(msg.media, chunk_size=512):
        await response.write(chunk)
    return response

app = web.Application()
app.add_routes(routes)
web.run_app(app,host='0.0.0.0')

When the download link is hit in the browser,the file is well streamed. Resume capability is well supported in Chrome, I expect the download manager to be well supported resume capability, but after the pause hits and starts downloading again,download manager unable to continue downloading and requires user to restart download. The message IDM gives: "When trying to resume the download, internet download manager got response from the server that it does not support resuming the download ..."

Lonami
  • 5,945
  • 2
  • 20
  • 38
Amin
  • 23
  • 1
  • 9
  • Seems like an issue with `IDM`, the `aiohttp` and `telethon` part look correct to me. You even claimed Chrome has no trouble with this. – Lonami Oct 18 '19 at 10:27
  • Yes. I have no problem with Chrome. Do I need to write extra code for `http` header Or was it done in `teleton` ? – Amin Oct 18 '19 at 10:51
  • Oh also, you should use the `offset=` parameter in `iter_download` to "resume from a byte offset". But even then, it doesn't explain why IDM fails. – Lonami Oct 18 '19 at 11:08

1 Answers1

3

Basing ourselves on this streamer implementation, it seems like you are missing Content-Range and status=206 to indicate Partial Content.

Probably something like the following might work. Note that it doesn't do enough validation (i.e. the Range from the headers may be invalid).

import re

...

async def handle(request):
    offset = request.headers.get('Range', 0)
    if not isinstance(offset, int):
        offset = int(re.match(r'bytes=(\d+)', offset).group(1))

    size = message.file.size
    response = web.StreamResponse(
        headers={
            'Content-Type': 'application/octet-stream',
            'Accept-Ranges': 'bytes',
            'Content-Range': f'bytes {offset}-{size}/{size}'
        },
        status=206 if offset else 200,
    )
    await response.prepare(request)

    async for part in client.iter_download(message.media, offset=offset):
        await response.write(part)

    return response
Lonami
  • 5,945
  • 2
  • 20
  • 38
  • When I set up ‍‍‍‍`status=206 if offset else 200` it goes into Chrome easily `pause` and `start` but inside `IDM` button `start` and `pause` not activated. When I set `status=206` into Chrome it is failed ,but it activates on `IDM` `start` and `pause` but when I hit `pause` and `start` download, the following error occurs:`telethon.errors.rpcerrorlist.LimitInvalidError: An invalid limit was provided. See https://core.telegram.org/api/files#downloading-files (caused by GetFileRequest)` – Amin Oct 19 '19 at 20:44
  • I test `webgram` on my server, but it has problem with `IDM` too.Inside `IDM` buttons start and pause not activated, but inside chrome everything is good – Amin Oct 19 '19 at 21:13
  • `LimitInvalidError` should be handled correctly by `iter_download`, so this may be a bug in the library. – Lonami Oct 20 '19 at 16:05
  • I found out that `aiohttp` has problem with `IDM` and it is not relate to `telethon` package – Amin Oct 21 '19 at 08:55