From c693a977448e291aa1c8febbcc2f6887da6ecd6a Mon Sep 17 00:00:00 2001 From: Apkawa Date: Fri, 3 Apr 2009 09:41:47 +0400 Subject: [PATCH] nya --- Apkawa/for_torrents.ru/benc.py | 132 ++++++++++++++ Apkawa/for_torrents.ru/torrent_parser.py | 84 +++++++++ Apkawa/for_torrents.ru/urllib2_file.py | 294 +++++++++++++++++++++++++++++++ 3 files changed, 510 insertions(+) create mode 100755 Apkawa/for_torrents.ru/benc.py create mode 100755 Apkawa/for_torrents.ru/torrent_parser.py create mode 100755 Apkawa/for_torrents.ru/urllib2_file.py diff --git a/Apkawa/for_torrents.ru/benc.py b/Apkawa/for_torrents.ru/benc.py new file mode 100755 index 0000000..7089ca8 --- /dev/null +++ b/Apkawa/for_torrents.ru/benc.py @@ -0,0 +1,132 @@ +from types import IntType, LongType, StringType, ListType, TupleType, DictType +from types import BooleanType +from types import UnicodeType +from cStringIO import StringIO + +def decode_int(x, f): + f += 1 + newf = x.index('e', f) + n = int(x[f:newf]) + if x[f] == '-': + if x[f + 1] == '0': + raise ValueError + elif x[f] == '0' and newf != f+1: + raise ValueError + return (n, newf+1) + +def decode_string(x, f): + colon = x.index(':', f) + n = int(x[f:colon]) + if x[f] == '0' and colon != f+1: + raise ValueError + colon += 1 + return (x[colon:colon+n], colon+n) + +def decode_list(x, f): + r, f = [], f+1 + while x[f] != 'e': + v, f = decode_func[x[f]](x, f) + r.append(v) + return (r, f + 1) + +def decode_dict(x, f): + r, f = {}, f+1 + lastkey = None + while x[f] != 'e': + k, f = decode_string(x, f) + if lastkey >= k: + raise ValueError + lastkey = k + r[k], f = decode_func[x[f]](x, f) + return (r, f + 1) + +decode_func = {} +decode_func['l'] = decode_list +decode_func['d'] = decode_dict +decode_func['i'] = decode_int +decode_func['0'] = decode_string +decode_func['1'] = decode_string +decode_func['2'] = decode_string +decode_func['3'] = decode_string +decode_func['4'] = decode_string +decode_func['5'] = decode_string +decode_func['6'] = decode_string +decode_func['7'] = decode_string +decode_func['8'] = decode_string +decode_func['9'] = decode_string + +def bdecode(x, sloppy = 0): + try: + r, l = decode_func[x[0]](x, 0) + except (IndexError, KeyError, ValueError): + raise ValueError, "bad bencoded data" + if not sloppy and l != len(x): + raise ValueError, "bad bencoded data" + return r + +bencached_marker = [] + +class Bencached: + def __init__(self, s): + self.marker = bencached_marker + self.bencoded = s + +BencachedType = type(Bencached('')) # insufficient, but good as a filter + +def encode_bencached(x,r): + assert x.marker == bencached_marker + r.append(x.bencoded) + +def encode_int(x,r): + r.extend(('i',str(x),'e')) + +def encode_bool(x,r): + encode_int(int(x),r) + +def encode_string(x,r): + r.extend((str(len(x)),':',x)) + +def encode_unicode(x,r): + encode_string(x.encode('UTF-8'),r) + +def encode_list(x,r): + r.append('l') + for e in x: + encode_func[type(e)](e, r) + r.append('e') + +def encode_dict(x,r): + r.append('d') + ilist = x.items() + ilist.sort() + for k,v in ilist: + r.extend((str(len(k)),':',k)) + encode_func[type(v)](v, r) + r.append('e') + +encode_func = {} +encode_func[BencachedType] = encode_bencached +encode_func[IntType] = encode_int +encode_func[LongType] = encode_int +encode_func[StringType] = encode_string +encode_func[ListType] = encode_list +encode_func[TupleType] = encode_list +encode_func[DictType] = encode_dict +if BooleanType: + encode_func[BooleanType] = encode_bool +if UnicodeType: + encode_func[UnicodeType] = encode_unicode + + +class EncError(ValueError): + def __str__(self): + return "%s"%self.args + +def bencode(x): + r = [] + try: + encode_func[type(x)](x, r) + except: + raise EncError("*** error *** could not encode type %s (value: %s)" % (type(x), x)) + return ''.join(r) + diff --git a/Apkawa/for_torrents.ru/torrent_parser.py b/Apkawa/for_torrents.ru/torrent_parser.py new file mode 100755 index 0000000..edaa473 --- /dev/null +++ b/Apkawa/for_torrents.ru/torrent_parser.py @@ -0,0 +1,84 @@ +#from django.contrib.sites.admin import Site +from hashlib import sha1 +import base64 +from benc import bencode, bdecode + +class TorrentParser: + meta = {} + meta_info = {} + def __init__(self): + pass + def parse_file(self, _file ): + self.meta = bdecode(_file) + self.meta_info = self.meta['info'] + def get_name(self): + return self.meta_info['name'] + def get_info_hash(self): + return sha1( bencode(self.meta_info)).digest() + def get_info_hash_base64(self): + return base64.b64encode(self.get_info_hash()) + def get_size(self): + files = self.meta_info.get('files') + if files: + return sum([f['length'] for f in files]) + else: + return self.meta_info['length'] + def get_file(self): + return bencode(self.meta) + def get_filenames_and_size(self, json=True): + files = self.meta_info.get('files') + if files: + file_and_size = [ { + 'file':'/'.join(f.get('path.utf-8') or f.get('path')), + 'size': f['length']} for f in files ] + else: + file_and_size = [{ + 'file': self.meta_info.get('name.utf-8') or self.meta_info.get('name') , + 'size':self.meta_info['length'] + }] + if json: + from json import dumps + return dumps( file_and_size ) + + pass + def get_all_announce_str(self, delimiter='|'): + anon = [self.meta['announce']] + anon_list = self.meta.get('announce-list') + if anon_list: + anon.extend( [ m[0] for m in anon_list]) + return delimiter.join(list(set(anon))) + def add_in_announce_list(self, url, end=False): + if self.meta.get('announce-list'): + if end: + self.meta['announce-list'].append([url]) + else: + self.meta['announce-list'].insert(0,[url]) + else: + self.meta['announce-list'] = [[url], [self.meta['announce']]] + + + +if __name__ == '__main__': + f = open('/home/apkawa/Code/test/download.torrent', 'r') + tp = TorrentParser() + tp.parse_file(f.read()) + f.close() + print dir(tp) + #print tp.meta + #print tp.meta_info + print tp.get_name() + print tp.get_info_hash() + print tp.get_info_hash_base64() + print tp.get_size() + print tp.meta['announce'] + #print tp.meta['announce-list'] + print tp.get_all_announce_str() + tp.add_in_announce_list('http://nya.org.ru/lalalal') + #print tp.meta['announce-list'] + print tp.get_filenames_and_size() + print len(tp.get_filenames_and_size()) + #e = open('/home/apkawa/Code/test/test-nya.torrent', 'w') + #e.write(tp.get_file()) + #e.close() + + diff --git a/Apkawa/for_torrents.ru/urllib2_file.py b/Apkawa/for_torrents.ru/urllib2_file.py new file mode 100755 index 0000000..f7e714b --- /dev/null +++ b/Apkawa/for_torrents.ru/urllib2_file.py @@ -0,0 +1,294 @@ +#!/usr/bin/env python +#### +# Version: 0.2.0 +# - UTF-8 filenames are now allowed (Eli Golovinsky)
+# - File object is no more mandatory, Object only needs to have seek() read() attributes (Eli Golovinsky)
+# +# Version: 0.1.0 +# - upload is now done with chunks (Adam Ambrose) +# +# Version: older +# THANKS TO: +# bug fix: kosh @T aesaeion.com +# HTTPS support : Ryan Grow + +# Copyright (C) 2004,2005,2006 Fabien SEISEN +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# you can contact me at: +# http://fabien.seisen.org/python/ +# +# Also modified by Adam Ambrose (aambrose @T pacbell.net) to write data in +# chunks (hardcoded to CHUNK_SIZE for now), so the entire contents of the file +# don't need to be kept in memory. +# +""" +enable to upload files using multipart/form-data + +idea from: +upload files in python: + http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/146306 + +timeoutsocket.py: overriding Python socket API: + http://www.timo-tasi.org/python/timeoutsocket.py + http://mail.python.org/pipermail/python-announce-list/2001-December/001095.html + +import urllib2_files +import urllib2 +u = urllib2.urlopen('http://site.com/path' [, data]) + +data can be a mapping object or a sequence of two-elements tuples +(like in original urllib2.urlopen()) +varname still need to be a string and +value can be string of a file object +eg: + ((varname, value), + (varname2, value), + ) + or + { name: value, + name2: value2 + } + +""" + +import os +import socket +import sys +import stat +import mimetypes +import mimetools +import httplib +import urllib +import urllib2 + +#CHUNK_SIZE = 65536 +CHUNK_SIZE = 2048 +PROGRESS = 0 + +def get_content_type(filename): + return mimetypes.guess_type(filename)[0] or 'application/octet-stream' + +# if sock is None, juste return the estimate size +def send_data(v_vars, v_files, boundary, sock=None): + l = 0 + for (k, v) in v_vars: + buffer='' + buffer += '--%s\r\n' % boundary + buffer += 'Content-Disposition: form-data; name="%s"\r\n' % k + buffer += '\r\n' + buffer += v + '\r\n' + if sock: + sock.send(buffer) + l += len(buffer) + for (k, v) in v_files: + fd = v + file_size = os.fstat(fd.fileno())[stat.ST_SIZE] + name = fd.name.split('/')[-1] + if isinstance(name, unicode): + name = name.encode('UTF-8') + buffer='' + buffer += '--%s\r\n' % boundary + buffer += 'Content-Disposition: form-data; name="%s"; filename="%s"\r\n' \ + % (k, name) + buffer += 'Content-Type: %s\r\n' % get_content_type(name) + buffer += 'Content-Length: %s\r\n' % file_size + buffer += '\r\n' + + l += len(buffer) + + sent = 0 + if sock: + sock.send(buffer) + if hasattr(fd, 'seek'): + fd.seek(0) + while True: + chunk = fd.read(CHUNK_SIZE) + sent += len(chunk) + PROGRESS = int(float(sent)/ float(file_size)*100) + #global PROGRESS + if not chunk: break + sock.send(chunk) + + l += file_size + buffer = '\r\n' + buffer += '--%s--\r\n' % boundary + buffer += '\r\n' + if sock: + sock.send(buffer) + l += len(buffer) + return l + +# mainly a copy of HTTPHandler from urllib2 +class newHTTPHandler(urllib2.BaseHandler): + def http_open(self, req): + return self.do_open(httplib.HTTP, req) + + def do_open(self, http_class, req): + data = req.get_data() + v_files=[] + v_vars=[] + # mapping object (dict) + if req.has_data() and type(data) != str: + if hasattr(data, 'items'): + data = data.items() + else: + try: + if len(data) and not isinstance(data[0], tuple): + raise TypeError + except TypeError: + ty, va, tb = sys.exc_info() + raise TypeError, "not a valid non-string sequence or mapping object", tb + + for (k, v) in data: + if hasattr(v, 'read'): + v_files.append((k, v)) + else: + v_vars.append( (k, v) ) + # no file ? convert to string + if len(v_vars) > 0 and len(v_files) == 0: + data = urllib.urlencode(v_vars) + v_files=[] + v_vars=[] + host = req.get_host() + if not host: + raise urllib2.URLError('no host given') + + h = http_class(host) # will parse host:port + if req.has_data(): + h.putrequest('POST', req.get_selector()) + if not 'Content-type' in req.headers: + if len(v_files) > 0: + boundary = mimetools.choose_boundary() + l = send_data(v_vars, v_files, boundary) + h.putheader('Content-Type', + 'multipart/form-data; boundary=%s' % boundary) + h.putheader('Content-length', str(l)) + else: + h.putheader('Content-type', + 'application/x-www-form-urlencoded') + if not 'Content-length' in req.headers: + h.putheader('Content-length', '%d' % len(data)) + else: + h.putrequest('GET', req.get_selector()) + + scheme, sel = urllib.splittype(req.get_selector()) + sel_host, sel_path = urllib.splithost(sel) + h.putheader('Host', sel_host or host) + for name, value in self.parent.addheaders: + name = name.capitalize() + if name not in req.headers: + h.putheader(name, value) + for k, v in req.headers.items(): + h.putheader(k, v) + # httplib will attempt to connect() here. be prepared + # to convert a socket error to a URLError. + try: + h.endheaders() + except socket.error, err: + raise urllib2.URLError(err) + + if req.has_data(): + if len(v_files) >0: + l = send_data(v_vars, v_files, boundary, h) + elif len(v_vars) > 0: + # if data is passed as dict ... + data = urllib.urlencode(v_vars) + h.send(data) + else: + # "normal" urllib2.urlopen() + h.send(data) + + code, msg, hdrs = h.getreply() + fp = h.getfile() + if code == 200: + resp = urllib.addinfourl(fp, hdrs, req.get_full_url()) + resp.code = code + resp.msg = msg + return resp + else: + return self.parent.error('http', req, fp, code, msg, hdrs) + +urllib2._old_HTTPHandler = urllib2.HTTPHandler +urllib2.HTTPHandler = newHTTPHandler + +class newHTTPSHandler(newHTTPHandler): + def https_open(self, req): + return self.do_open(httplib.HTTPS, req) + +urllib2.HTTPSHandler = newHTTPSHandler + +if __name__ == '__main__': + import getopt + import urllib2 + import urllib2_file + import string + import sys + + def usage(progname): + print """ +SYNTAX: %s -u url -f file [-v] +""" % progname + + try: + opts, args = getopt.getopt(sys.argv[1:], 'hvu:f:') + except getopt.GetoptError, errmsg: + print "ERROR:", errmsg + sys.exit(1) + + v_url = '' + v_verbose = 0 + v_file = '' + + for name, value in opts: + if name in ('-h',): + usage(sys.argv[0]) + sys.exit(0) + elif name in ('-v',): + v_verbose += 1 + elif name in ('-u',): + v_url = value + elif name in ('-f',): + v_file = value + else: + print "invalid argument:", name + sys.exit(2) + + error = 0 + if v_url == '': + print "need -u" + error += 1 + if v_file == '': + print "need -f" + error += 1 + + if error > 0: + sys.exit(3) + + fd = open(v_file, 'r') + data = { + 'filename' : fd, + } + # u = urllib2.urlopen(v_url, data) + req = urllib2.Request(v_url, data, {}) + try: + u = urllib2.urlopen(req) + except urllib2.HTTPError, errobj: + print "HTTPError:", errobj.code + + else: + buf = u.read() + print "OK" -- 2.11.4.GIT