(file) Return to btmakemetafile.py CVS log (file) (dir) Up to [Development] / bittornado

  1 theshadow 1.1 #!/usr/bin/env python
  2               
  3               # Written by Bram Cohen
  4               # multitracker extensions by John Hoffman
  5               # see LICENSE.txt for license information
  6               
  7 theshadow 1.2 from BitTornado import PSYCO
  8 theshadow 1.1 if PSYCO.psyco:
  9                   try:
 10                       import psyco
 11                       assert psyco.__version__ >= 0x010100f0
 12                       psyco.full()
 13                   except:
 14                       pass
 15               
 16               from sys import argv, version, exit
 17               assert version >= '2', "Install Python 2.0 or greater"
 18               from os.path import getsize, split, join, abspath, isdir
 19               from os import listdir
 20               from sha import sha
 21               from copy import copy
 22               from string import strip
 23 theshadow 1.2 from BitTornado.bencode import bencode
 24 theshadow 1.3 from BitTornado.BT1.btformats import check_info
 25 theshadow 1.2 from BitTornado.parseargs import parseargs, formatDefinitions
 26 theshadow 1.1 from threading import Event
 27               from time import time
 28               
 29               defaults = [
 30                   ('announce_list', '',
 31                       'a list of announce URLs - explained below'),
 32                   ('piece_size_pow2', 0,
 33                       "which power of 2 to set the piece size to (0 = automatic)"),
 34                   ('comment', '',
 35                       "optional human-readable comment to put in .torrent"),
 36                   ('target', '',
 37                       "optional target file for the torrent")
 38                   ]
 39               
 40               default_piece_len_exp = 18
 41               
 42               ignore = ['core', 'CVS']
 43               
 44               def print_announcelist_details():
 45                   print ('    announce_list = optional list of redundant/backup tracker URLs, in the format:')
 46                   print ('           url[,url...][|url[,url...]...]')
 47 theshadow 1.1     print ('                where URLs separated by commas are all tried first')
 48                   print ('                before the next group of URLs separated by the pipe is checked.')
 49                   print ("                If none is given, it is assumed you don't want one in the metafile.")
 50                   print ('                If announce_list is given, clients which support it')
 51                   print ('                will ignore the <announce> value.')
 52                   print ('           Examples:')
 53                   print ('                http://tracker1.com|http://tracker2.com|http://tracker3.com')
 54                   print ('                     (tries trackers 1-3 in order)')
 55                   print ('                http://tracker1.com,http://tracker2.com,http://tracker3.com')
 56                   print ('                     (tries trackers 1-3 in a randomly selected order)')
 57                   print ('                http://tracker1.com|http://backup1.com,http://backup2.com')
 58                   print ('                     (tries tracker 1 first, then tries between the 2 backups randomly)')
 59               
 60               def dummy(v):
 61                   pass
 62               
 63               def make_meta_file(file, url, params = {}, flag = Event(),
 64                                  progress = dummy, progress_percent = 1):
 65                   if params.has_key('piece_size_pow2'):
 66                       piece_len_exp = params['piece_size_pow2']
 67                   else:
 68 theshadow 1.1         piece_len_exp = default_piece_len_exp
 69                   if params.has_key('target') and params['target'] != '':
 70                       f = params['target']
 71                   else:
 72                       a, b = split(file)
 73                       if b == '':
 74                           f = a + '.torrent'
 75                       else:
 76                           f = join(a, b + '.torrent')
 77                           
 78                   if piece_len_exp == 0:  # automatic
 79                       size = calcsize(file)
 80                       if   size > 8L*1024*1024*1024:   # > 8 gig =
 81                           piece_len_exp = 21          #   2 meg pieces
 82                       elif size > 2*1024*1024*1024:   # > 2 gig =
 83                           piece_len_exp = 20          #   1 meg pieces
 84                       elif size > 512*1024*1024:      # > 512M =
 85                           piece_len_exp = 19          #   512K pieces
 86                       elif size > 64*1024*1024:       # > 64M =
 87                           piece_len_exp = 18          #   256K pieces
 88                       elif size > 16*1024*1024:       # > 16M =
 89 theshadow 1.1             piece_len_exp = 17          #   128K pieces
 90                       elif size > 4*1024*1024:        # > 4M =
 91                           piece_len_exp = 16          #   64K pieces
 92                       else:                           # < 4M =
 93                           piece_len_exp = 15          #   32K pieces
 94                   piece_length = 2 ** piece_len_exp
 95                   
 96                   info = makeinfo(file, piece_length, flag, progress, progress_percent)
 97                   if flag.isSet():
 98                       return
 99                   check_info(info)
100                   h = open(f, 'wb')
101                   data = {'info': info, 'announce': strip(url), 'creation date': long(time())}
102                   if params.has_key('comment') and params['comment'] != '':
103                       data['comment'] = params['comment']
104                   if params.has_key('real_announce_list'):    # shortcut for progs calling in from outside
105                       data['announce-list'] = params['real_announce_list']
106                   elif params.has_key('announce_list') and params['announce_list'] != '':
107                       list = []
108                       for tier in params['announce_list'].split('|'):
109                           sublist = []
110 theshadow 1.1             for tracker in tier.split(','):
111                               sublist += [tracker]
112                           list += [sublist]
113                       data['announce-list'] = list
114                       
115                   h.write(bencode(data))
116                   h.close()
117               
118               def calcsize(file):
119                   if not isdir(file):
120                       return getsize(file)
121                   total = 0L
122                   for s in subfiles(abspath(file)):
123                       total += getsize(s[1])
124                   return total
125               
126               def makeinfo(file, piece_length, flag, progress, progress_percent=1):
127                   file = abspath(file)
128                   if isdir(file):
129                       subs = subfiles(file)
130                       subs.sort()
131 theshadow 1.1         pieces = []
132                       sh = sha()
133                       done = 0L
134                       fs = []
135                       totalsize = 0.0
136                       totalhashed = 0L
137                       for p, f in subs:
138                           totalsize += getsize(f)
139               
140                       for p, f in subs:
141                           pos = 0L
142                           size = getsize(f)
143                           fs.append({'length': size, 'path': p})
144                           h = open(f, 'rb')
145                           while pos < size:
146                               a = min(size - pos, piece_length - done)
147                               sh.update(h.read(a))
148                               if flag.isSet():
149                                   return
150                               done += a
151                               pos += a
152 theshadow 1.1                 totalhashed += a
153                               
154                               if done == piece_length:
155                                   pieces.append(sh.digest())
156                                   done = 0
157                                   sh = sha()
158                               if progress_percent:
159                                   progress(totalhashed / totalsize)
160                               else:
161                                   progress(a)
162                           h.close()
163                       if done > 0:
164                           pieces.append(sh.digest())
165                       return {'pieces': ''.join(pieces),
166                           'piece length': piece_length, 'files': fs, 
167                           'name': split(file)[1]}
168                   else:
169                       size = getsize(file)
170                       pieces = []
171                       p = 0L
172                       h = open(file, 'rb')
173 theshadow 1.1         while p < size:
174                           x = h.read(min(piece_length, size - p))
175                           if flag.isSet():
176                               return
177                           pieces.append(sha(x).digest())
178                           p += piece_length
179                           if p > size:
180                               p = size
181                           if progress_percent:
182                               progress(float(p) / size)
183                           else:
184                               progress(min(piece_length, size - p))
185                       h.close()
186                       return {'pieces': ''.join(pieces), 
187                           'piece length': piece_length, 'length': size, 
188                           'name': split(file)[1]}
189               
190               def subfiles(d):
191                   r = []
192                   stack = [([], d)]
193                   while len(stack) > 0:
194 theshadow 1.1         p, n = stack.pop()
195                       if isdir(n):
196                           for s in listdir(n):
197                               if s not in ignore and s[:1] != '.':
198                                   stack.append((copy(p) + [s], join(n, s)))
199                       else:
200                           r.append((p, n))
201                   return r
202               
203               def prog(amount):
204                   print '%.1f%% complete\r' % (amount * 100),
205               
206               if __name__ == '__main__':
207                   if len(argv) < 3:
208                       a,b = split(argv[0])
209                       print 'Usage: ' + b + ' <trackerurl> <file> [file...] [params...]'
210                       print
211                       print formatDefinitions(defaults, 80)
212                       print_announcelist_details()
213                       print ('')
214                       exit(2)
215 theshadow 1.1 
216                   try:
217                       config, args = parseargs(argv[1:], defaults, 2, None)
218                       for file in args[1:]:
219                           make_meta_file(file, args[0], config, progress = prog)
220                   except ValueError, e:
221                       print 'error: ' + str(e)
222                       print 'run with no args for parameter explanations'

No CVS admin address has been configured
Powered by
ViewCVS 0.9.3