#! /Usr/bin/ENV Python
# Written by Bram Cohen and Myers carpenter
# See license.txt for license information
#
# File name: btdownloadgui. py
# Code reading diary: 2004-9-2
# Pen: zfive5
#
# Today, I decided to open the seed file to start analysis on the BT client.
# For better understanding, I analyzed the source code in the window2000 environment, and double-click. torrent under the Resource Manager.
# File, then we will see the BT client that we are all very familiar with. Let's select the file directory ....
# Perception tells me that the seed file name is passed into the BT client through a parameter call and opened registration through regedit
# Table we can find the following clues:
#
# Windows Registry Editor Version 5.00
#
# [Hkey_classes_root/. torrent]
##= "BitTorrent"
# "Content type" = "application/X-BitTorrent"
#
# [Hkey_classes_root/BitTorrent]
##= "Torrent file"
# "Editflags" = HEX: 00, 01,00
#
# [Hkey_classes_root/BitTorrent/Shell]
# @ = "Open"
#
# [Hkey_classes_root/BitTorrent/Shell/edit]
##= "Edit torrent with torrentedit"
#
# [Hkey_classes_root/BitTorrent/Shell/edit/command]
# @ = "/" C: // program files // btdwv // torrentedit.exe/"-- torrentfile/" % 1 /""
#
# [Hkey_classes_root/BitTorrent/Shell/Open]
#
# [Hkey_classes_root/BitTorrent/Shell/Open/command]
# @ = "/" C: // program files // btdwv // btdownloadgui.exe/"-- responsefile/" % 1 /""
#
# The system is executed:
# C:/program files/btdwv/btdownloadgui.exe -- responsefile E:/help. CHM. torrent
#
# Analyze the following file now...
# You can directly go to the definition section of class btwxapp (wxapp ).
#
From sys import argv
From BitTorrent import version
From BitTorrent. Download import download
From btdownloadheadless import print_spew
From threading import event, thread
From OS. Path import join, split, exists
From OS import getcwd
From wxpython. wx import *
From time import strftime, time
From webbrowser import open_new
From traceback import print_exc
# Calculate the time function second-> (hour: minute: second)
Def hours (n ):
If n =-1:
Return''
If n = 0:
Return 'complete! '
N = int (N)
H, r = divmod (n, 60*60)
M, SEC = divmod (R, 60)
If H> 1000000:
Return''
If H> 0:
Return '% d hour % 02d min % 02d sec' % (H, M, Sec)
Else:
Return '% D min % 02d sec' % (M, Sec)
Wxevt_invoke = wxneweventtype ()
# I am not clear about events or other things. You can skip this step.
Def evt_invoke (Win, func ):
Win. Connect (-1,-1, wxevt_invoke, func)
# Same as above
Class invokeevent (wxpyevent ):
Def _ init _ (self, func, argS, kwargs ):
Wxpyevent. _ init _ (Self)
Self. seteventtype (wxevt_invoke)
Self. func = func
Self. ARGs = ARGs
Self. kwargs = kwargs
# Download the main form class. This is also true through perception.
Class downloadinfoframe:
# This is a class constructor.
Def _ init _ (self, flag ):
Frame = wxframe (none,-1, 'bittorrent '+ version + 'Download', size = wxsize (400,250 ))
Self. Frame = frame
Self. Flag = Flag
Self. uiflag = event ()
Self. Fin = false
Self. last_update_time = 0
Self. showing_error = false
Panel = wxpanel (frame,-1)
Colsizer = wxflexgridsizer (Cols = 1, vgap = 3)
Fnsizer = wxboxsizer (wxhorizontal)
Self. filenametext = wxstatictext (panel,-1, '', style = wxalign_left)
Fnsizer. Add (self. filenametext, 1, wxalign_bottom)
Self. abouttext = wxstatictext (panel,-1, 'about', style = wxalign_right)
Self. abouttext. setforegroundcolour ('blue ')
Self. abouttext. setfont (wxfont (14, wxnormal, true ))
Fnsizer. Add (self. abouttext, 0, wxexpand)
Colsizer. Add (fnsizer, 0, wxexpand)
Self. Gauge = wxgauge (panel,-1, range = 1000, style = wxga_smooth)
Colsizer. Add (self. gauge, 0, wxexpand)
Gridsizer = wxflexgridsizer (Cols = 2, vgap = 3, hgap = 8)
Gridsizer. Add (wxstatictext (panel,-1, 'Estimated time left :'))
Self. timeesttext = wxstatictext (panel,-1 ,'')
Gridsizer. Add (self. timeesttext, 0, wxexpand)
Gridsizer. Add (wxstatictext (panel,-1, 'Download :'))
Self. filedesttext = wxstatictext (panel,-1 ,'')
Gridsizer. Add (self. filedesttext, 0, wxexpand)
Gridsizer. addgrowablecol (1)
Rategridsizer = wxflexgridsizer (Cols = 4, vgap = 3, hgap = 8)
Rategridsizer. Add (wxstatictext (panel,-1, 'Download rate :'))
Self. downratetext = wxstatictext (panel,-1 ,'')
Rategridsizer. Add (self. downratetext, 0, wxexpand)
Rategridsizer. Add (wxstatictext (panel,-1, 'downloaded :'))
Self. downtotaltext = wxstatictext (panel,-1 ,'')
Rategridsizer. Add (self. downtotaltext, 0, wxexpand)
Rategridsizer. Add (wxstatictext (panel,-1, 'upload rate :'))
Self. upratetext = wxstatictext (panel,-1 ,'')
Rategridsizer. Add (self. upratetext, 0, wxexpand)
Rategridsizer. Add (wxstatictext (panel,-1, 'uploaded :'))
Self. uptotaltext = wxstatictext (panel,-1 ,'')
Rategridsizer. Add (self. uptotaltext, 0, wxexpand)
Rategridsizer. addgrowablecol (1)
Rategridsizer. addgrowablecol (3)
Colsizer. Add (gridsizer, 0, wxexpand)
Colsizer. Add (rategridsizer, 0, wxexpand)
Colsizer. Add (50, 50, 0, wxexpand)
Self. cancelbutton = wxbutton (panel,-1, 'cancel ')
Colsizer. Add (self. cancelbutton, 0, wxalign_center)
Colsizer. addgrowablecol (0)
Colsizer. addgrowablerow (3)
Border = wxboxsizer (wxhorizontal)
Border. Add (colsizer, 1, wxexpand | wxall, 4)
Panel. setsizer (Border)
Panel. setautolayout (true)
Evt_left_down (self. abouttext, self. Donate)
Evt_close (frame, self. Done)
Evt_button (frame, self. cancelbutton. GETID (), self. Done)
Evt_invoke (frame, self. oninvoke)
Self. Frame. Show ()
# Some event processing functions and auxiliary functions below
Def donate (self, event ):
Thread (target = self. donate2). Start ()
Def donate2 (Self ):
Open_new ('HTTP: // bitconjurer.org/bittor#/donate.html ')
Def oninvoke (self, event ):
If not self. uiflag. isset ():
Apply (event. func, event. ARGs, event. kwargs)
Def invokelater (self, func, argS = [], kwargs = {}):
If not self. uiflag. isset ():
Wxpostevent (self. Frame, invokeevent (func, argS, kwargs ))
Def updatestatus (self, d ):
If (self. last_update_time + 0.1 <time () and not self. showing_error) or D. get ('fractiondone') in (0.0, 1.0) or D. has_key ('active '):
Self. invokelater (self. onupdatestatus, [d])
Def onupdatestatus (self, d ):
Try:
If D. has_key ('spew '):
Print_spew (d ['spew'])
Activity = D. Get ('active ')
Fractiondone = D. Get ('fractiondone ')
Timeest = D. Get ('timeest ')
Downrate = D. Get ('downrate ')
Uprate = D. Get ('uprate ')
Downtotal = D. Get ('Download ')
Uptotal = D. Get ('uptotal ')
If activity is not none and not self. Fin:
Self. timeesttext. setlabel (activity)
If fractiondone is not none and not self. Fin:
Self. gauge. setvalue (INT (fractiondone * 1000 ))
Self. Frame. settitle ('% d % s-BitTorrent % s' % (INT (fractiondone * 100), self. filename, Version ))
If timeest is not none:
Self. timeesttext. setlabel (hours (timeest ))
If downrate is not none:
Self. downratetext. setlabel ('%. 0f kib/s' % (float (downrate)/(1 <10 )))
If uprate is not none:
Self. upratetext. setlabel ('%. 0f kib/s' % (float (uprate)/(1 <10 )))
If downtotal is not none:
Self. downtotaltext. setlabel ('%. 1f m' % (downtotal ))
If uptotal is not none:
Self. uptotaltext. setlabel ('%. 1f m' % (uptotal ))
Self. last_update_time = Time ()
Except t:
Print_ex ()
Def finished (Self ):
Self. Fin = true
Self. invokelater (self. onfinishevent)
Def failed (Self ):
Self. Fin = true
Self. invokelater (self. onfailevent)
Def error (self, errormsg ):
If not self. showing_error:
Self. invokelater (self. onerrorevent, [errormsg])
Def onfinishevent (Self ):
Self. timeesttext. setlabel ('Download succeeded! ')
Self. cancelbutton. setlabel ('close ')
Self. gauge. setvalue (1000)
Self. Frame. settitle ('% s-upload-BitTorrent % s' % (self. filename, Version ))
Self. downratetext. setlabel ('')
Def onfailevent (Self ):
Self. timeesttext. setlabel ('failed! ')
Self. cancelbutton. setlabel ('close ')
Self. gauge. setvalue (0)
Self. downratetext. setlabel ('')
Def onerrorevent (self, errormsg ):
Self. showing_error = true
DLG = wxmessagedialog (self. Frame, message = errormsg,
Caption = 'Download error', style = wxok | wxicon_error)
DLG. Fit ()
DLG. Center ()
DLG. showmodal ()
Self. showing_error = false
Def choosefile (self, default, size, saveas, DIR ):
If saveas:
Return saveas
F = event ()
Bucket = [none]
Self. invokelater (self. onchoosefile, [default, bucket, F, size, Dir])
F. Wait ()
Return bucket [0]
Def onchoosefile (self, default, bucket, F, size, DIR ):
If dir:
DL = wxdirdialog (self. Frame, 'Choose a directory to save to, pick a partial download to resume ',
Join (getcwd (), default), style = wxdd_default_style | wxdd_new_dir_button)
Else:
DL = wxfiledialog (self. Frame, 'Choose file to save as, pick a partial download to resume ', '', default,' *. * ', wxsave)
If DL. showmodal ()! = Wxid_ OK:
Self. Done (none)
Else:
Bucket [0] = DL. getpath ()
Self. filenametext. setlabel ('% s (%. 1f MB)' % (default, float (size)/(1 <20 )))
Self. timeesttext. setlabel ('starting up ...')
Self. filedesttext. setlabel (DL. getpath ())
Self. filename = default
Self. Frame. settitle (default + '-BitTorrent' + version)
F. Set ()
Def newpath (self, PATH ):
Self. filedesttext. setlabel (PATH)
Def done (self, event ):
Self. uiflag. Set ()
Self. Flag. Set ()
Self. Frame. Destroy ()
# This is the BT app class. The starting position of Bt, and Params is the command line parameter.
Class btwxapp (wxapp ):
Def _ init _ (self, X, Params ):
Self. Params = Params
Wxapp. _ init _ (self, X)
# This member function is a bit like the bool ctestv1app: initinstance () member function in MFC (this is the result of my years of VC use)
# The preceding main form class is created and a Thread class is started.
#
Def oninit (Self ):
Doneflag = event ()
D = downloadinfoframe (doneflag)
Self. settopwindow (D. Frame)
Thread = thread (target = Next, argS = [self. Params, D, doneflag])
Thread. setdaemon (false)
Thread. Start ()
Return 1
# Here is the entry function of the BT client.
Def run (Params ):
Try:
APP = btwxapp (0, Params)
App. mainloop ()
Except t:
Print_exc ()
# Thread processing functions, which is also the core process of BT
Def next (Params, D, doneflag ):
Try:
# This section is a bit confusing
P = join (split (argv [0]) [0], 'donated ')
If not exists (P) and long (Time () % 3 = 0:
Open_new ('HTTP: // bitconjurer.org/bittor#/donate.html ')
DLG = wxmessagedialog (D. Frame, 'bittorrent is donation supported software. '+
'Please go to the donation page (which shocould be appearing for you now) and make a donation from there. '+
'Or you can click NO and donate later./N/nhave you made a donation yet? ',
'Donate! ', Wxyes_no | wxicon_information | wxno_default)
If DLG. showmodal () = wxid_yes:
DLG. Destroy ()
DLG = wxmessagedialog (D. Frame, 'Thanks for your donation! You will no longer be shown donation requests./N/N' +
"If you haven't actually made a donation and are feeling guilty (as you shoshould !) You can always get to "+
"The donation page by clicking the 'About' link in the upper-right corner of the main BitTorrent window and" +
'Donating from there. ', 'Thanks! ', Wxok)
DLG. showmodal ()
DLG. Destroy ()
Try:
Open (p, 'wb '). Close ()
Handle t ioerror, E:
DLG = wxmessagedialog (D. Frame, "Sorry, but I couldn't set the flag to not ask you for donations in the future-" + STR (e ),
'Sorry! ', Wxok | wxicon_error)
DLG. showmodal ()
DLG. Destroy ()
Else:
DLG. Destroy ()
# This is another function we will talk about below.
Download (Params, D. choosefile, D. updatestatus, D. Finished, D. error, doneflag, 100, D. newpath)
If not D. Fin:
D. Failed ()
Except t:
Print_exc ()
# It calls the run function. The input command line parameter is -- responsefile E:/help. CHM. torrent.
If _ name _ = '_ main __':
Run (argv [1:])
# Analyze it here (to be continued)