#!/usr/bin/python3 from urllib.parse import urlparse, parse_qs, unquote import sys import json import tempfile import subprocess import os import ox import ox.web.auth import pandora_client import requests CHUNK_SIZE = 1024 * 8 base_url = 'https://cdosea.0x2620.org' api = None def get_api(): global api if not api: api = pandora_client.API(base_url + '/api/') r = api.signin(**ox.web.auth.get('cdosea')) if r['status']['code'] != 200: print('failed to signin') print(r) sys.exit(1) def parse_url(url): params = url.split('downloads/')[1].split('/') file_id, recipient_id, security_hash = '', '', '' if len(params) > 2: # https://www.wetransfer.com/downloads/XXXXXXXXXX/YYYYYYYYY/ZZZZZZZZ file_id, recipient_id, security_hash = params else: # The url is similar to https://www.wetransfer.com/downloads/XXXXXXXXXX/ZZZZZZZZ file_id, security_hash = params return file_id, recipient_id, security_hash def download(url): # resolve redirect url = requests.get(url).url file_id, recipient_id, security_hash = parse_url(url) url_t = 'https://wetransfer.com/api/ui/transfers/{file_id}/{security_hash}/download?recipient_id={recipient_id}' url = url_t.format( file_id=file_id, recipient_id=recipient_id, security_hash=security_hash ) r = requests.get(url) download_data = r.json() print('Downloading {0}...'.format(url)) offset = 0 if 'direct_link' in download_data: direct_link_path = urlparse(download_data['direct_link']).path direct_link_path = direct_link_path.split('/') filename = unquote(direct_link_path[-1]) # FIXME: does wetransfer support Range requests? ''' if os.path.exists(filename): offset = os.path.getsize(filename) resume_header = {'Range': 'bytes=%d-' % offset} r = requests.get(download_data['direct_link'], headers=resume_header, stream=True) else: ''' r = requests.get(download_data['direct_link'], stream=True) else: filename = unquote(download_data['fields']['filename']) r = requests.post( download_data['formdata']['action'], data=download_data['fields'], stream=True ) file_size = int(r.headers['Content-Length']) if offset: outputfile = open(filename, 'ab') else: outputfile = open(filename, 'wb') counter = 0 for chunk in r.iter_content(chunk_size=CHUNK_SIZE): if chunk: outputfile.write(chunk) outputfile.flush() done = counter * CHUNK_SIZE + offset sys.stdout.write( '\r%0.2f%% %s/%s' % ( done * 100/file_size, done, file_size ) ) counter += 1 outputfile.close() if os.path.getsize(filename) != file_size: print('\nFailed to download') sys.exit(1) sys.stdout.write('\r100% {0}/{1}\n'.format(file_size, file_size)) print('Finished! {0}'.format(filename)) return filename def upload(filename): if os.path.exists(filename): # files > 4GB fail with unzip #subprocess.call(['unzip', filename]) subprocess.call(['jar', 'xf', filename]) ids = [] for root, folders, files in os.walk('.'): for f in ox.sorted_strings(files): if f.endswith('.zip') or f.startswith('._'): continue f = os.path.join(root, f) if '__MACOSX' in f: continue h = upload_file(f) ids.append(h) get_api() items = set() for id in ids: r = api.getMediaInfo(id=id)['data'] items.add(r['item']) l = api.addList(name=os.path.basename(filename))['data']['id'] api.addListItems(list=l, items=list(items)) def upload_file(f): get_api() filename = os.path.basename(f) # register file with pan.do/ra info = ox.avinfo(f) oshash = info['oshash'] r = api.getMediaInfo(id=oshash)['data'] if 'item' in r: return oshash if 'path' in info: del info['path'] r = api.addMedia({ 'id': oshash, 'filename': filename, 'info': info }) # dont upload again if file is known if r['status']['text'] == 'file exists': return oshash # upload media file tmp = tempfile.gettempdir() api._resume_file = os.path.join(tmp, 'pandora_client.%s.%s.json' % (os.environ.get('USER'), oshash)) url = '%s/api/upload/direct/' % base_url r = api.upload_chunks(url, f, { 'id': oshash }) return oshash def main(url): if url.startswith('http'): filename = download(url) else: filename = url upload(filename) if __name__ == '__main__': argv = sys.argv[1:] if len(argv) != 1: print('%s url' % sys.argv[0]) sys.exit(1) main(argv[0])