├── 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 | --------------------------------------------------------------------------------