3
# Written by Bram Cohen
4
# modified for multitracker by John Hoffman
5
# see LICENSE.txt for license information
7
from BitTornado import PSYCO
11
assert psyco.__version__ >= 0x010100f0
16
from sys import argv, version
18
from BitTornado.BT1.makemetafile import make_meta_file, completedir
19
from threading import Event, Thread
20
from BitTornado.bencode import bdecode
23
from os.path import join, isdir
25
from wxPython.wx import *
27
print 'wxPython is either not installed or has not been installed properly.'
36
wxEVT_INVOKE = wxNewEventType()
38
def EVT_INVOKE(win, func):
39
win.Connect(-1, -1, wxEVT_INVOKE, func)
41
class InvokeEvent(wxPyEvent):
42
def __init__(self, func, args, kwargs):
43
wxPyEvent.__init__(self)
44
self.SetEventType(wxEVT_INVOKE)
51
frame = wxFrame(None, -1, 'BitTorrent Torrent File Maker', size = wxSize(550, 410))
54
panel = wxPanel(frame, -1)
56
gridSizer = wxFlexGridSizer(cols = 2, rows = 2, vgap = 0, hgap = 8)
58
gridSizer.Add(wxStaticText(panel, -1, 'make torrent of:'))
60
b = wxBoxSizer(wxHORIZONTAL)
61
self.dirCtl = wxTextCtrl(panel, -1, '')
62
b.Add(self.dirCtl, 1, wxEXPAND)
63
b.Add((10, 10), 0, wxEXPAND)
65
button = wxButton(panel, -1, 'dir', size = (30,20))
66
EVT_BUTTON(frame, button.GetId(), self.selectdir)
69
button2 = wxButton(panel, -1, 'file', size = (30,20))
70
EVT_BUTTON(frame, button2.GetId(), self.selectfile)
73
gridSizer.Add(b, 0, wxEXPAND)
74
gridSizer.Add(wxStaticText(panel, -1, ''))
75
gridSizer.Add(wxStaticText(panel, -1, ''))
77
gridSizer.Add(wxStaticText(panel, -1, 'announce url:'))
78
self.annCtl = wxTextCtrl(panel, -1, 'http://my.tracker:6969/announce')
79
gridSizer.Add(self.annCtl, 0, wxEXPAND)
80
gridSizer.Add(wxStaticText(panel, -1, ''))
81
gridSizer.Add(wxStaticText(panel, -1, ''))
83
a = wxFlexGridSizer(cols = 1)
84
a.Add(wxStaticText(panel, -1, 'announce list:'))
85
a.Add(wxStaticText(panel, -1, ''))
86
abutton = wxButton(panel, -1, 'copy\nannounces\nfrom\ntorrent', size = (50,70))
87
EVT_BUTTON(frame, abutton.GetId(), self.announcecopy)
88
a.Add(abutton, 0, wxEXPAND)
89
gridSizer.Add(a, 0, wxEXPAND)
91
self.annListCtl = wxTextCtrl(panel, -1, '\n\n\n\n\n', wxPoint(-1,-1), (400,120),
92
wxTE_MULTILINE|wxHSCROLL|wxTE_DONTWRAP)
93
gridSizer.Add(self.annListCtl, -1, wxEXPAND)
95
gridSizer.Add(wxStaticText(panel, -1, ''))
96
exptext = wxStaticText(panel, -1,
97
"a list of announces separated by commas " +
98
"or whitespace and on several lines -\n" +
99
"trackers on the same line will be tried randomly," +
100
"and all the trackers on one line\n" +
101
"will be tried before the trackers on the next line.")
102
exptext.SetFont(wxFont(6, wxDEFAULT, wxNORMAL, wxNORMAL, False))
103
gridSizer.Add(exptext)
105
gridSizer.Add(wxStaticText(panel, -1, ''))
106
gridSizer.Add(wxStaticText(panel, -1, ''))
108
gridSizer.Add(wxStaticText(panel, -1, 'piece size:'))
109
self.piece_length = wxChoice(panel, -1,
110
choices = ['automatic', '2MiB', '1MiB', '512KiB', '256KiB', '128KiB', '64KiB', '32KiB'])
111
self.piece_length_list = [0, 21, 20, 19, 18, 17, 16, 15]
112
self.piece_length.SetSelection(0)
113
gridSizer.Add(self.piece_length)
115
gridSizer.Add(wxStaticText(panel, -1, ''))
116
gridSizer.Add(wxStaticText(panel, -1, ''))
118
gridSizer.Add(wxStaticText(panel, -1, 'comment:'))
119
self.commentCtl = wxTextCtrl(panel, -1, '')
120
gridSizer.Add(self.commentCtl, 0, wxEXPAND)
122
gridSizer.AddGrowableCol(1)
124
border = wxBoxSizer(wxVERTICAL)
125
border.Add(gridSizer, 0, wxEXPAND | wxNORTH | wxEAST | wxWEST, 25)
126
b2 = wxButton(panel, -1, 'make')
127
border.Add((10, 10), 1, wxEXPAND)
128
border.Add(b2, 0, wxALIGN_CENTER | wxSOUTH, 20)
129
EVT_BUTTON(frame, b2.GetId(), self.complete)
130
panel.SetSizer(border)
131
panel.SetAutoLayout(True)
133
panel.DragAcceptFiles(True)
134
EVT_DROP_FILES(panel, self.selectdrop)
136
def selectdir(self, x):
137
dl = wxDirDialog(self.frame, style = wxDD_DEFAULT_STYLE | wxDD_NEW_DIR_BUTTON)
138
if dl.ShowModal() == wxID_OK:
139
self.dirCtl.SetValue(dl.GetPath())
141
def selectfile(self, x):
142
dl = wxFileDialog (self.frame, 'Choose file or directory to use', style = wxOPEN)
143
if dl.ShowModal() == wxID_OK:
144
self.dirCtl.SetValue(dl.GetPath())
146
def selectdrop(self, x):
150
self.dirCtl.SetValue(x[0])
152
def announcecopy(self, x):
153
dl = wxFileDialog (self.frame, 'Choose .torrent file to use', '', '', '*.torrent', wxOPEN)
154
if dl.ShowModal() == wxID_OK:
156
h = open(dl.GetPath(), 'rb')
157
metainfo = bdecode(h.read())
159
self.annCtl.SetValue(metainfo['announce'])
160
if metainfo.has_key('announce-list'):
162
for tier in metainfo['announce-list']:
164
list += [tracker, ', ']
170
self.annListCtl.SetValue(liststring+'\n\n')
172
self.annListCtl.SetValue('')
176
def getannouncelist(self):
178
for t in self.annListCtl.GetValue().split('\n'):
180
t = t.replace(',',' ')
181
for tr in t.split(' '):
188
def complete(self, x):
189
if self.dirCtl.GetValue() == '':
190
dlg = wxMessageDialog(self.frame, message = 'You must select a\n file or directory',
191
caption = 'Error', style = wxOK | wxICON_ERROR)
195
params = {'piece_size_pow2': self.piece_length_list[self.piece_length.GetSelection()]}
196
annlist = self.getannouncelist()
198
params['real_announce_list'] = annlist
199
comment = self.commentCtl.GetValue()
201
params['comment'] = comment
203
CompleteDir(self.dirCtl.GetValue(), self.annCtl.GetValue(), params)
208
from traceback import print_exc
211
def __init__(self, d, a, params):
216
self.separatetorrents = False
219
self.choicemade = Event()
220
frame = wxFrame(None, -1, 'BitTorrent make torrent', size = (1,1))
222
panel = wxPanel(frame, -1)
223
gridSizer = wxFlexGridSizer(cols = 1, vgap = 8, hgap = 8)
224
gridSizer.AddGrowableRow(1)
225
gridSizer.Add(wxStaticText(panel, -1,
226
'Do you want to make a separate .torrent'),0,wxALIGN_CENTER)
227
gridSizer.Add(wxStaticText(panel, -1,
228
'for every item in this directory?'),0,wxALIGN_CENTER)
229
gridSizer.Add(wxStaticText(panel, -1, ''))
231
b = wxFlexGridSizer(cols = 3, hgap = 10)
232
yesbut = wxButton(panel, -1, 'Yes')
233
def saidyes(e, self = self):
235
self.separatetorrents = True
237
EVT_BUTTON(frame, yesbut.GetId(), saidyes)
240
nobut = wxButton(panel, -1, 'No')
241
def saidno(e, self = self):
244
EVT_BUTTON(frame, nobut.GetId(), saidno)
247
cancelbut = wxButton(panel, -1, 'Cancel')
248
def canceled(e, self = self):
250
EVT_BUTTON(frame, cancelbut.GetId(), canceled)
252
gridSizer.Add(b, 0, wxALIGN_CENTER)
253
border = wxBoxSizer(wxHORIZONTAL)
254
border.Add(gridSizer, 1, wxEXPAND | wxALL, 4)
256
panel.SetSizer(border)
257
panel.SetAutoLayout(True)
266
if self.separatetorrents:
267
frame = wxFrame(None, -1, 'BitTorrent make directory', size = wxSize(550, 250))
269
frame = wxFrame(None, -1, 'BitTorrent make torrent', size = wxSize(550, 250))
272
panel = wxPanel(frame, -1)
273
gridSizer = wxFlexGridSizer(cols = 1, vgap = 15, hgap = 8)
275
if self.separatetorrents:
276
self.currentLabel = wxStaticText(panel, -1, 'checking file sizes')
278
self.currentLabel = wxStaticText(panel, -1, 'building ' + self.d + '.torrent')
279
gridSizer.Add(self.currentLabel, 0, wxEXPAND)
280
self.gauge = wxGauge(panel, -1, range = 1000, style = wxGA_SMOOTH)
281
gridSizer.Add(self.gauge, 0, wxEXPAND)
282
gridSizer.Add((10, 10), 1, wxEXPAND)
283
self.button = wxButton(panel, -1, 'cancel')
284
gridSizer.Add(self.button, 0, wxALIGN_CENTER)
285
gridSizer.AddGrowableRow(2)
286
gridSizer.AddGrowableCol(0)
288
g2 = wxFlexGridSizer(cols = 1, vgap = 15, hgap = 8)
289
g2.Add(gridSizer, 1, wxEXPAND | wxALL, 25)
293
panel.SetAutoLayout(True)
294
EVT_BUTTON(frame, self.button.GetId(), self.done)
295
EVT_CLOSE(frame, self.done)
296
EVT_INVOKE(frame, self.onInvoke)
298
Thread(target = self.complete).start()
302
if self.separatetorrents:
303
completedir(self.d, self.a, self.params, self.flag,
304
self.valcallback, self.filecallback)
306
make_meta_file(self.d, self.a, self.params, self.flag,
307
self.valcallback, progress_percent = 1)
308
if not self.flag.isSet():
309
self.currentLabel.SetLabel('Done!')
310
self.gauge.SetValue(1000)
311
self.button.SetLabel('Close')
313
except (OSError, IOError), e:
314
self.currentLabel.SetLabel('Error!')
315
self.button.SetLabel('Close')
316
dlg = wxMessageDialog(self.frame, message = 'Error - ' + str(e),
317
caption = 'Error', style = wxOK | wxICON_ERROR)
321
def valcallback(self, amount):
322
self.invokeLater(self.onval, [amount])
324
def onval(self, amount):
325
self.gauge.SetValue(int(amount * 1000))
327
def filecallback(self, f):
328
self.invokeLater(self.onfile, [f])
331
self.currentLabel.SetLabel('building ' + join(self.d, f) + '.torrent')
333
def onInvoke(self, event):
334
if not self.flag.isSet():
335
apply(event.func, event.args, event.kwargs)
337
def invokeLater(self, func, args = [], kwargs = {}):
338
if not self.flag.isSet():
339
wxPostEvent(self.frame, InvokeEvent(func, args, kwargs))
341
def done(self, event):
345
class btWxApp(wxApp):
349
self.SetTopWindow(d.frame)
352
if __name__ == '__main__':