├── Procfile
├── README.md
├── bot.py
├── requirements.txt
└── uploader.py
/Procfile:
--------------------------------------------------------------------------------
1 | worker: python3 bot.py
2 |
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # wetransferBot
2 | Wetransfer Uploader Telegram Bot
3 |
4 | ## It can Upload Files Remotly Through Url.
5 |
6 | ## it Have some Limits For Uploading File
7 |
8 | ```
9 | Just Replace Bot Token in bot.py And You ready To Deploy it .
10 |
11 | note: it May be contains some bug. I am not working On It.
12 | ```
13 | # Credit : sorry Not able find That repo For Credit But Everything Is mentioned in uploader.py file.
14 |
--------------------------------------------------------------------------------
/bot.py:
--------------------------------------------------------------------------------
1 |
2 | import json
3 | from telegram.ext import CommandHandler,MessageHandler, Filters,Updater
4 | from telegram import ParseMode
5 | from telegram.ext.dispatcher import run_async
6 | import os , sys
7 | import uploader
8 | from pySmartDL import SmartDL
9 |
10 |
11 |
12 |
13 |
14 |
15 | ######################################################################################
16 | bot_token ='YOUR_BOT_TOKEN_HERE' #
17 |
18 | updater = Updater(token= bot_token, use_context=True) #
19 |
20 | dp = updater.dispatcher #
21 | #
22 |
23 | ######################################################################################
24 |
25 |
26 |
27 | def help(update, context):
28 | context.bot.send_message(chat_id=update.message.chat_id, text="I am in Beta",parse_mode=telegram.ParseMode.HTML)
29 |
30 | @run_async
31 | def start(update,context):
32 | context.bot.send_message(chat_id =update.message.chat_id,text ="Hey Send me a direct link")
33 |
34 | @run_async
35 | def download(update,context):
36 |
37 | url = update.message.text
38 | url =url.split()
39 | sent_message =context.bot.send_message(chat_id=update.message.chat_id,text ="Trying To download ....")
40 |
41 | # dest = "C:\\Downloads\\" # or '~/Downloads/' on linux
42 | dest = "Downloads/"
43 | # dest = "Downloads\\" #For windows
44 |
45 | try:
46 | obj = SmartDL(url, dest)
47 | obj.start()
48 |
49 | sent_message.edit_text("Downloading complete")
50 | DownloadStatus = True
51 |
52 | except Exception as e :
53 | print(e)
54 | sent_message.edit_text("Downloading error :{}".format(e))
55 | DownloadStatus = False
56 |
57 | filename = obj.get_dest()
58 | print(filename)
59 | # filename = download_file(url)
60 | try:
61 | if DownloadStatus:
62 | sent_message.edit_text("Uploading Your file")
63 | wurl = uploader.upload([filename])
64 | sent_message.edit_text(" Full Link : Download".format(wurl),parse_mode=ParseMode.HTML)
65 |
66 | try:
67 | os.remove(filename)
68 | print("file Removed")
69 | except Exception as e:
70 | print(e)
71 | except Exception as e :
72 | print(e)
73 | if DownloadStatus:
74 | sent_message.edit_text("Uploading fail :".format(e))
75 | try:
76 | os.remove(filename)
77 | print("file Removed")
78 | except Exception as e:
79 | print(e)
80 |
81 | start_handler = CommandHandler('start', start)
82 | dp.add_handler(start_handler)
83 |
84 | downloader_handler = MessageHandler(Filters.regex(r'http' ), download)
85 | dp.add_handler(downloader_handler)
86 |
87 | help_handler = CommandHandler('help',help)
88 | dp.add_handler(help_handler)
89 |
90 |
91 |
92 | updater.start_polling()
93 | updater.idle()
94 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | python-telegram-bot==12.0.0b1
2 | requests
3 | pySmartDL
4 | urllib3
5 |
--------------------------------------------------------------------------------
/uploader.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | #
4 | # Copyright (c) 2018-2019 Leonardo Taccari
5 | # All rights reserved.
6 | #
7 | # Redistribution and use in source and binary forms, with or without
8 | # modification, are permitted provided that the following conditions
9 | # are met:
10 | #
11 | # 1. Redistributions of source code must retain the above copyright
12 | # notice, this list of conditions and the following disclaimer.
13 | # 2. Redistributions in binary form must reproduce the above copyright
14 | # notice, this list of conditions and the following disclaimer in the
15 | # documentation and/or other materials provided with the distribution.
16 | #
17 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 | # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 | # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
21 | # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 | # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 | # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 | # POSSIBILITY OF SUCH DAMAGE.
28 | #
29 |
30 |
31 | """
32 | Download/upload files via wetransfer.com
33 |
34 | transferwee is a script/module to download/upload files via wetransfer.com.
35 |
36 | It exposes `download' and `upload' subcommands, respectively used to download
37 | files from a `we.tl' or `wetransfer.com/downloads' URLs and upload files that
38 | will be shared via emails or link.
39 | """
40 |
41 |
42 | from typing import List
43 | import os.path
44 | import urllib.parse
45 | import zlib
46 |
47 | import requests
48 |
49 |
50 | WETRANSFER_API_URL = 'https://wetransfer.com/api/v4/transfers'
51 | WETRANSFER_DOWNLOAD_URL = WETRANSFER_API_URL + '/{transfer_id}/download'
52 | WETRANSFER_UPLOAD_EMAIL_URL = WETRANSFER_API_URL + '/email'
53 | WETRANSFER_UPLOAD_LINK_URL = WETRANSFER_API_URL + '/link'
54 | WETRANSFER_FILES_URL = WETRANSFER_API_URL + '/{transfer_id}/files'
55 | WETRANSFER_PART_PUT_URL = WETRANSFER_FILES_URL + '/{file_id}/part-put-url'
56 | WETRANSFER_FINALIZE_MPP_URL = WETRANSFER_FILES_URL + '/{file_id}/finalize-mpp'
57 | WETRANSFER_FINALIZE_URL = WETRANSFER_API_URL + '/{transfer_id}/finalize'
58 |
59 | WETRANSFER_DEFAULT_CHUNK_SIZE = 5242880
60 |
61 |
62 | def download_url(url: str) -> str:
63 | """Given a wetransfer.com download URL download return the downloadable URL.
64 |
65 | The URL should be of the form `https://we.tl/' or
66 | `https://wetransfer.com/downloads/'. If it is a short URL (i.e. `we.tl')
67 | the redirect is followed in order to retrieve the corresponding
68 | `wetransfer.com/downloads/' URL.
69 |
70 | The following type of URLs are supported:
71 | - `https://we.tl/`:
72 | received via link upload, via email to the sender and printed by
73 | `upload` action
74 | - `https://wetransfer.com//`:
75 | directly not shared in any ways but the short URLs actually redirect to
76 | them
77 | - `https://wetransfer.com///`:
78 | received via email by recipients when the files are shared via email
79 | upload
80 |
81 | Return the download URL (AKA `direct_link') as a str or None if the URL
82 | could not be parsed.
83 | """
84 | # Follow the redirect if we have a short URL
85 | if url.startswith('https://we.tl/'):
86 | r = requests.head(url, allow_redirects=True)
87 | url = r.url
88 |
89 | recipient_id = None
90 | params = url.replace('https://wetransfer.com/downloads/', '').split('/')
91 |
92 | if len(params) == 2:
93 | transfer_id, security_hash = params
94 | elif len(params) == 3:
95 | transfer_id, recipient_id, security_hash = params
96 | else:
97 | return None
98 |
99 | j = {
100 | "security_hash": security_hash,
101 | }
102 | if recipient_id:
103 | j["recipient_id"] = recipient_id
104 | r = requests.post(WETRANSFER_DOWNLOAD_URL.format(transfer_id=transfer_id),
105 | json=j)
106 |
107 | j = r.json()
108 | return j.get('direct_link')
109 |
110 |
111 | def download(url: str) -> None:
112 | """Given a `we.tl/' or `wetransfer.com/downloads/' download it.
113 |
114 | First a direct link is retrieved (via download_url()), the filename will
115 | be extracted to it and it will be fetched and stored on the current
116 | working directory.
117 | """
118 | dl_url = download_url(url)
119 | file = urllib.parse.urlparse(dl_url).path.split('/')[-1]
120 |
121 | r = requests.get(dl_url, stream=True)
122 | with open(file, 'wb') as f:
123 | for chunk in r.iter_content(chunk_size=1024):
124 | f.write(chunk)
125 |
126 |
127 | def _file_name_and_size(file: str) -> dict:
128 | """Given a file, prepare the "name" and "size" dictionary.
129 |
130 | Return a dictionary with "name" and "size" keys.
131 | """
132 | filename = os.path.basename(file)
133 | filesize = os.path.getsize(file)
134 |
135 | return {
136 | "name": filename,
137 | "size": filesize
138 | }
139 |
140 |
141 | def _prepare_email_upload(filenames: List[str], message: str,
142 | sender: str, recipients: List[str]) -> str:
143 | """Given a list of filenames, message a sender and recipients prepare for
144 | the email upload.
145 |
146 | Return the parsed JSON response.
147 | """
148 | j = {
149 | "files": [_file_name_and_size(f) for f in filenames],
150 | "from": sender,
151 | "message": message,
152 | "recipients": recipients,
153 | "ui_language": "en",
154 | }
155 |
156 | r = requests.post(WETRANSFER_UPLOAD_EMAIL_URL, json=j)
157 | return r.json()
158 |
159 |
160 | def _prepare_link_upload(filenames: List[str], message: str) -> str:
161 | """Given a list of filenames and a message prepare for the link upload.
162 |
163 | Return the parsed JSON response.
164 | """
165 | j = {
166 | "files": [_file_name_and_size(f) for f in filenames],
167 | "message": message,
168 | "ui_language": "en",
169 | }
170 |
171 | r = requests.post(WETRANSFER_UPLOAD_LINK_URL, json=j)
172 | return r.json()
173 |
174 |
175 | def _prepare_file_upload(transfer_id: str, file: str) -> str:
176 | """Given a transfer_id and file prepare it for the upload.
177 |
178 | Return the parsed JSON response.
179 | """
180 | j = _file_name_and_size(file)
181 | r = requests.post(WETRANSFER_FILES_URL.format(transfer_id=transfer_id),
182 | json=j)
183 | return r.json()
184 |
185 |
186 | def _upload_chunks(transfer_id: str, file_id: str, file: str,
187 | default_chunk_size: int = WETRANSFER_DEFAULT_CHUNK_SIZE) -> str:
188 | """Given a transfer_id, file_id and file upload it.
189 |
190 | Return the parsed JSON response.
191 | """
192 | f = open(file, 'rb')
193 |
194 | chunk_number = 0
195 | while True:
196 | chunk = f.read(default_chunk_size)
197 | chunk_size = len(chunk)
198 | if chunk_size == 0:
199 | break
200 | chunk_number += 1
201 |
202 | j = {
203 | "chunk_crc": zlib.crc32(chunk),
204 | "chunk_number": chunk_number,
205 | "chunk_size": chunk_size,
206 | "retries": 0
207 | }
208 |
209 | r = requests.post(
210 | WETRANSFER_PART_PUT_URL.format(transfer_id=transfer_id,
211 | file_id=file_id),
212 | json=j)
213 | url = r.json().get('url')
214 | r = requests.options(url,
215 | headers={
216 | 'Origin': 'https://wetransfer.com',
217 | 'Access-Control-Request-Method': 'PUT',
218 | })
219 | r = requests.put(url, data=chunk)
220 |
221 | j = {
222 | 'chunk_count': chunk_number
223 | }
224 | r = requests.put(
225 | WETRANSFER_FINALIZE_MPP_URL.format(transfer_id=transfer_id,
226 | file_id=file_id),
227 | json=j)
228 |
229 | return r.json()
230 |
231 |
232 | def _finalize_upload(transfer_id: str) -> str:
233 | """Given a transfer_id finalize the upload.
234 |
235 | Return the parsed JSON response.
236 | """
237 | r = requests.put(WETRANSFER_FINALIZE_URL.format(transfer_id=transfer_id))
238 |
239 | return r.json()
240 |
241 |
242 | def upload(files: List[str], message: str = '', sender: str = None,
243 | recipients: List[str] = []) -> str:
244 | """Given a list of files upload them and return the corresponding URL.
245 |
246 | Also accepts optional parameters:
247 | - `message': message used as a description of the transfer
248 | - `sender': email address used to receive an ACK if the upload is
249 | successfull. For every download by the recipients an email
250 | will be also sent
251 | - `recipients': list of email addresses of recipients. When the upload
252 | succeed every recipients will receive an email with a link
253 |
254 | If both sender and recipient parameters are passed the email upload will be
255 | used. Otherwise, the link upload will be used.
256 |
257 | Return the short URL of the transfer on success.
258 | """
259 |
260 | # Check that all files exists
261 | for f in files:
262 | if not os.path.exists(f):
263 | raise FileNotFoundError(f)
264 |
265 | # Check that there are no duplicates filenames
266 | # (despite possible different dirname())
267 | filenames = [os.path.basename(f) for f in files]
268 | if len(files) != len(set(filenames)):
269 | raise FileExistsError('Duplicate filenames')
270 |
271 | transfer_id = None
272 | if sender and recipients:
273 | # email upload
274 | transfer_id = \
275 | _prepare_email_upload(files, message, sender, recipients)['id']
276 | else:
277 | # link upload
278 | transfer_id = _prepare_link_upload(files, message)['id']
279 |
280 | for f in files:
281 | file_id = _prepare_file_upload(transfer_id, f)['id']
282 | _upload_chunks(transfer_id, file_id, f)
283 |
284 | return _finalize_upload(transfer_id)['shortened_url']
285 |
286 |
287 |
--------------------------------------------------------------------------------