File size: 2,722 Bytes
f46e223
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import streamSaver from 'streamsaver'
import { Api } from 'telegram'
import { req } from './Fetcher'
import { telegramClient } from './Telegram'

export async function download(id: string): Promise<ReadableStream> {
  const { data: response } = await req.get(`/files/${id}`, { params: { raw: 1, as_array: 1 } })
  let cancel = false

  const client = await telegramClient.connect()
  const readableStream = new ReadableStream({
    start(_controller: ReadableStreamDefaultController) {
    },
    async pull(controller: ReadableStreamDefaultController) {
      let countFiles = 1
      console.log('start downloading:', response.files)

      const promises = response.files.map(async (file) => {
        let chat: any
        if (file.forward_info && file.forward_info.match(/^channel\//gi)) {
          const [type, peerId, id, accessHash] = file.forward_info.split('/')
          let peer: Api.InputPeerChannel | Api.InputPeerUser | Api.InputPeerChat
          if (type === 'channel') {
            peer = new Api.InputPeerChannel({
              channelId: BigInt(peerId) as any,
              accessHash: BigInt(accessHash as string) as any })
            chat = await client.invoke(new Api.channels.GetMessages({
              channel: peer,
              id: [new Api.InputMessageID({ id: Number(id) })]
            }))
          }
        } else {
          chat = await client.invoke(new Api.messages.GetMessages({
            id: [new Api.InputMessageID({ id: Number(file.message_id) })]
          }))
        }

        const getData = async () => await client.downloadMedia(chat['messages'][0].media, {
          outputFile: {
            write: (chunk: Buffer) => {
              if (cancel) return false
              return controller.enqueue(chunk)
            },
            close: () => {
              if (countFiles++ >= Number(response.files.length))
                controller.close()
            }
          },
          progressCallback: (received, total) => {
            console.log('progress: ', (Number(received)/Number(total)*100).toFixed(2), '%')
          }
        })

        return getData()
      })

      await Promise.all(promises)
    },
    cancel() {
      cancel = true
    }
  }, {
    size(chunk: any) {
      return chunk.length
    }
  })
  return readableStream
}

export const directDownload = async (id: string, name: string): Promise<void> => {
  const fileStream = streamSaver.createWriteStream(name)
  const writer = fileStream.getWriter()
  const reader = (await download(id)).getReader()
  const pump = () => reader.read().then(({ value, done }) => {
    if (done) return writer.close()
    writer.write(value)
    return writer.ready.then(pump)
  })
  await pump()

}