Changes

Jump to navigation Jump to search
17,295 bytes removed ,  15:02, 27 September 2019
no edit summary
{{TOCright}}
 
==Introduction==
{{eyecatch|Note|You have to set an API key in your profile before auto-creqing with Avdump GUI.}}
 
{{Avdump-gui}}
 
'''For Vista and Windows 7 permission issues on installation:'''
*Create a blank .bat file.
*Insert this text into it and modify it to your situation:<br> <tt>"C:\Windows\System32\msiExec.exe" -i "C:\Directory\Where\Located\avdump-gui.msi"</tt>
*Right click and run the .bat file as administrator.
==Changelog==
<pre>
v1v2.05 42 - 1308.1101.20072019 *available as auto update* thx to rar for fixing dumping of files with characters in non local codepage* Avdump2 Build 7080 added
v1v2.04 41 - 1005.1101.20072019 *available as auto update* fix for not being able * show error message about too long paths * fallback to dump files with japanese characters cp437 in the filename avdump 0.32 added and changes implementedcase shell encoding fails which i guess should work?
v1v2.40 - 03 - 13.0501.20072019 *available as auto update* * Avdump2 Build 7070 added the console again fix for log, export and done pathes with spaces added parents for the dialogs so they die with the program and can't stay open anymore option 9 added (experimental mp3 hashing for ostdb) v1.02 - 13.05.2007 added error and warning dialog boxes to prevent a couple problems added some exceptionhandling for * show errors in filelist if we encounter one while processing a few fields v1.01 - 12.05.2007 killed a nasty bug with trailing \ in the scanpath v1.00 - 12.05.2007 Initial release</pre>file instead of endless retrying
==Source== v2.33 - 09.11.2016 *available as auto update*This gui was coded purely in python using wxpython for the framework. * new icon * progressbar and status not updating
<pre style="fontv2.32 -size: 60%;">09.11.2016 *available as auto update*import wx,os,subprocessw,sys * options not being stored on initial start
class mainFrame(wx v2.Frame): __simple = ['p','z','r','m','c','o','9'] __options = {'avdump':'avdump31 - 09.exe','user':'','pass':'','ext':'','misc':'','bsize':'2048:1','port':'','tout':'30','retries':'6','exp':'export11.txt','log':'log.txt','done':'done.txt'}2016 *available as auto update* __configfile='config.ini' * fixed drag and drop
def read_config(self,newconfig=''): '''read the config file and return the content''' if not os v2.path30 - 03.exists(self11.__configfile):2016 *available as auto update* for elem in self * ported from python 2.__options: newconfig += ('%s=%s\n') %(elem,self7 to 3.__options[elem])4 file * path/filename encoding woes fixed(self.__configfile,"w").write(newconfig?) for line in file(self.__configfile,"r").readlines(): if not line.endswith('='): temp,val = line.rstrip('\n').split('=',1) else: val = '' for elem in self.__options: if temp == elem: self.__options[temp] = val * export option removed and made implicit to be always enabled
def __init__(self, parent, title): wx.Frame.__init__(self, parent, -1, u'Avdump GUI', wx.DefaultPosition, (350, 140), style=wx.CLOSE_BOX | wx.SYSTEM_MENU | wx.CAPTION | 0 | 0 | wx.MINIMIZE_BOX) self.panel = wx.Panel(self, -1) self.filepath = wx.TextCtrl(self v2.panel, 20 -1, '', (95, 25), size=(190, 24)) self.start = wx18.Button(self08.panel, -1, 'Start', (90,75), (-1, -1))2015 *available as auto update* self.options = wx.Button(self.panel, -1, 'Options', (185,75), (-1, -1)) * Avdump2 Build 6714 added self.select = wx.Button(self.panel, -1, '...', (295, 25), (25, -1)) self.scantype = wx.RadioBox(self.panel,-1,pos=(5,5),size=(-1, 59),style=wx.RA_VERTICAL,label='scantype',choices = ['Files','Folder']) self.Bind(wx.EVT_BUTTON, self.selectClick, self.select) self.Bind(wx.EVT_BUTTON, self.optionsClick, self.options) self.Bind(wx.EVT_BUTTON, self.startClick, self.start) self.child = OptionsFrame(self, 'App') * dependencies updated
def selectClick(self, event,path=''): if self v2.scantype19 - 11.GetStringSelection() == 'Files': dialog = wx11.FileDialog ( self, message = 'Pick a directory.', style= wx.FD_MULTIPLE)2012 *available as msi installer & auto update* if dialog.ShowModal() == wx.ID_OK: temp = dialog.GetPaths() * Avdump2 Build 6525 added if len(temp)>1: for elem in temp: path += '"' + elem + '" ' else: path = '"' + temp[0].rstrip("\\") + '"' else: dialog = wx.DirDialog ( self, message = 'Pick a directory.' ) if dialog.ShowModal() == wx.ID_OK: path = '"' + dialog.GetPath().rstrip("\\") + '"' self.filepath.Clear() dialog.Destroy() self.filepath.write(path) self.__options['scanpath'] = path * recompiled with updated dependencies which may or may not fix some issues or cause new ones
def startClick(self, event): self.read_config() self.__options['param'] = '' if self.filepath.GetValue() == '': self.child.error('You have to select some files or folder to scan!') elif (self.__options['user'] == '' or self.__options['pass'] == ''): self.child.error("You didn't enter your username and/or password in the options menu.") elif self.__options['avdump'] == '': self.child.error('You must specify the path to avdump.exe!') elif self.__options['avdump'] == 'avdump.exe': self.child v2.info('You should set the _absolute_ path to avdump.exe.\nOtherwise complications might arise.') else: if self.__options['misc'].lstrip(',') > 0: for elem in self.__options['misc'].split(','): if elem not in ['retries','']: if elem in self.__simple: self.__options['param'] += ' -' + elem elif elem == 'tout': self.__options['param'] += ' 18 -' + elem + ':' + self31.__options[elem] + ':' + self07.__options['retries']2012 *available as auto update* else: self.__options['param'] += ' -' + elem + ':' + self.__options[elem] '''debug option to see what avdump actually get's fed''' #self.child.info(('%s%s -ac:%s:%s %s') %(self.__options['avdump'], self.__options['param'], self.__options['user'], self.__options['pass'], self.__options['scanpath'])) arg = (u'%s%s -ac:%s:%s %s') %(self.__options['avdump'], self.__options['param'], self.__options['user'], self.__options['pass'], self.__options['scanpath']) print arg subprocessw.Popen(arg) * Avdump2 Build 5290 added
def optionsClick(self, event): self v2.17 - 21.child09.refresh()2011 *available as auto update* self.child.Show(True) * filename encoding issue fixed
class OptionsFrame v2.15 - 13.09.2011 * Avdump2 Build 5028 added * text fix (wxOptionen instead of Options.Framewatch out for da evil germanz ja): __box = {'ext':False,'log':False,'exp':False,'port':False,'done':False,'bsize':False,'tout':False,'c':False,'m':False,'p':False,'r':False,'z':False,'o':False,'9':False} * can now drop files into the table to process * speed improvement when adding lots of files at once (really only noticeable > 500) __options = {'avdump':'avdump.exe','user':'','pass':'','ext':'','misc':'','bsize':'2048:1','port':'','tout':'30','retries':'6','exp':' * potentially fixing some issue with the last filehash not being shown in the export.txt','log':'log.txt','done':'done.txt'} __configfile='config.ini'box
def read_config(self): '''read the config file and return the content''' if not os.path.exists(self.__configfile): self.write_config() for line in file(self.__configfile,"r") v2.readlines(): if not line14 - 11.endswith('='): temp,val = line09.rstrip('\n').split('=',1)2011 else: val = '' for elem in self.__options: if temp == elem: self.__options[temp] = val * Avdump2 Build 5000 added
def write_config(self,newconfig=''): for elem in self v2.13 - 06.09.__options:2011 newconfig += ('%s=%s\n') %(elem,self.__options[elem]) * Avdump2 Build 4991 added file(self.__configfile,"w").write(newconfig) * fixes to be compatible to the new Avdump2 CLI
def set_misc(self,misc=''): for elem in self v2.12 - 05.__box: if self09.__box[elem] is True:2011 *pulled* misc += elem + ',' self.__options['misc'] = misc * Avdump2 Build 4964 added
def get_checkboxes v2.11 - 01.07.2011 * trying to scan files without having provided a username/password -> BOOM (self,misctrying to kill the subprocess without it running): * removing already scanned files form the list and readding them will process them again even if misc "done" is not None:set misc = misc.rstrip (',')from frontend at least.lstrip(',') if miscavdump itself would ignore them.find(',') > 0: for elem this would leave a couple "new" entries in misc.split(','the list): self.__box[elem] = True else: self.__box[misc] = True
def __init__(self, parent, title): wx.Frame v2.__init__(self, parent, 10 -1, 'options', wx.DefaultPosition, (301, 691), style=wx.CLOSE_BOX | wx.SYSTEM_MENU | wx01.CAPTION | 0 | 0 | wx07.MINIMIZE_BOX)2011 self.panel = wx.Panel(self, -1) * Avdump2 Build 4334 added self.adoptions = wx.StaticBox(self.panel, -1, "advanced options", (5,170), (275, 290)) * Autoupdater implemented self.groupbox3 = wx.StaticBox(self.panel, -1, "Path to Avdump", (5,0), (275, 55)) * last scanned dir stored in config self.groupbox4 = wx.StaticBox(self.panel, -1, "UDP API Username/Password", (5,55), (275, 115)) self.groupbox5 = wx.StaticBox(self.panel, -1, "logs", (5,460), (275, 170)) self.filepath = wx.TextCtrl(self.panel, -1, '', (15,20), * window size=stored in config (220, 25)) self.selectavdump = wx.Button(self.panel, -1, '...unless it', (245,20), (25, 25)) self.username = wx.TextCtrl(self.panel, -1, '', (15,90), size=(255, 25)) self.password = wx.TextCtrl(self.panel, -1, '', (15,135), size=(255, 25)) self.delete = wx.CheckBox(self.panel, -1, 'delete files after parsing', (15,190), (240, 17)) self.recursive = wx.CheckBox(self.panel, -1, 'do _not_ recurse into subfolders', (15,205), (240, 17)) self.monitor = wx.CheckBox(self.panel, -1, 'Monitor folder(s)', (15,220), (240, 17)) self.mp3 = wx.CheckBox(self.panel, -1, 'ostdb mp3 test (experimental)', (15,235), (240, 17)) self.bsize = wx.CheckBox(self.panel, -1, 'overwrite the default setting for buffersize', (15,250), (240, 17)maximized) self.ext = wx.CheckBox(self.panel, -1, 'overwrite the default setting for extentions', (15,265), (240, 17)) self.port = wx.CheckBox(self.panel, -1, 'overwrite the default setting for port', (15,280), (240, 17)) self.tout = wx.CheckBox(self.panel, -1, 'overwrite the default setting for timeouts', (15,295), (240, 17)) self.pause = wx.CheckBox(self.panel, -1, 'Pause when done (hold cmd window)', (15,310), (240, 17)) self.random = wx.CheckBox(self.panel, -1, 'Random file order', (15,325), (240, 17)) self.wait = wx.CheckBox(self.panel, -1, 'wait for response when sending dumps', (15,340), (240, 17)) self.extention = wx.TextCtrl(self.panel, -1, '', (15,375), size=(255, 25)) self.buffersize = wx.TextCtrl(self.panel, -1, '', (15,420), size=(55, 25)) self.portnumber = wx.TextCtrl(self.panel, -1, '', (81,420), size=(55, 25)) self.timeout = wx.TextCtrl(self.panel, -1, '', (149,420), size=(55, 25)) self.retries = wx.TextCtrl(self.panel, -1, '', (215,420), size=(55, 25)) self.exp = wx.CheckBox(self.panel, -1, '', (15,493), (17, 17)) self.exppath = wx.TextCtrl(self.panel, -1, '', (35,490), size=(200, 25)) self.selectexp = wx.Button(self.panel, -1, '...', (245,490), (25, 23)) self.done = wx.CheckBox(self.panel, -1, '', (15,553), (17, 17)) self.donepath = wx.TextCtrl(self.panel, -1, '', (35,550), size=(200, 25)) self.selectdone = wx.Button(self.panel, -1, '...', (245,550), (25, 23)) self.log = wx.CheckBox(self.panel, -1, '', (15,598), (17, 17)) self.logpath = wx.TextCtrl(self.panel, -1, '', (35,595), size=(200, 25)) self.selectlog = wx.Button(self.panel, -1, '...', (245,595), (25, 23)) self.save = wx.Button(self.panel, -1, 'Save', (65,635), (75, 23)) self.cancel = wx.Button(self.panel, -1, 'Cancel', (150,635), (75, 23)) self.Retries = wx.StaticText(self.panel, -1, 'Retries:', (220,402), (44, 17)) self.Timeout = wx.StaticText(self.panel, -1, 'Timeout:', (152,402), (50, 17)) self.Buffersize = wx.StaticText(self.panel, -1, 'Buffersize:', (16,402), (60, 17)) self.Port = wx.StaticText(self.panel, -1, 'Port:', (86,402), (44, 17)) self.donelog = wx.StaticText(self.panel, -1, 'save processed-file-paths to file and exlude existing from proc', (40,520), (200, 25)) self.exported2k = wx.StaticText(self.panel, -1, 'export ed2k-links to file', (40,472), (150, 17)) self.writelog = wx.StaticText(self.panel, -1, 'write output * use stderr to log', (40,578), (150, 17)) self.apiuser = wx.StaticText(self.panel, -1, 'Username:', (20,73), (150, 17)) self.apipass = wx.StaticText(self.panel, -1, 'Password:', (20,118), (150, 17)) self.extentionlist = wx.StaticText(self.panel, -1, 'comma seperated extension list', (20,358), (170, 17)) self.Bind(wx.EVT_BUTTON, self.selectavdClick, self.selectavdump) self.Bind(wx.EVT_BUTTON, self.selectlogClick, self.selectlog) self.Bind(wx.EVT_BUTTON, self.selectexpClick, self.selectexp) self.Bind(wx.EVT_BUTTON, self.selectdoneClick, self.selectdone) self.Bind(wx.EVT_BUTTON, self.saveClick, self.save)catch errors instead of stdout self.Bind(wx.EVT_BUTTON, self.cancelClick, self.cancel) self.Bind(wx.EVT_CLOSE, self.onclose) self.refresh() * lots of rewriting
def selectavdClick(self, event): dialog = wx v2.02 - 09.FileDialog ( self, message = 'Pick a directory06.')2011 if dialog.ShowModal() == wx.ID_OK: * Avdump2 Build 4320 added self.filepath.Clear() * ditched subprocess module in favour of qprocess self.filepath.write(dialog.GetPath().rstrip * peek into console output and notice the user when an error happened ("\\")outdated version or wrong password/username)
def selectlogClick(self, event): dialog = wx v2.FileDialog ( self, message = 'Pick a directory01 - 06.') if dialog06.ShowModal() == wx.ID_OK:2011 self.logpath.Clear() * various nasty bugs removed self.logpath.write(dialog.GetPath().rstrip("\\")) * windows can be enlarged on demand
def selectexpClick(self, event): dialog = wx v2.FileDialog ( self, message = 'Pick a directory00 - 03.') if dialog06.ShowModal() == wx.ID_OK:2011 self.exppath.Clear() * Avdump2 Build 4260 added self.exppath.write(dialog.GetPath().rstrip("\\")) * rewrote the whole lot and simplified it
def selectdoneClick(self, event): dialog = wx v1.07 - 06.FileDialog ( self, message = 'Pick a directory04.')2008 if dialog.ShowModal() == wx * Avdump 0.ID_OK:34 added self.donepath.Clear() * fixed a bug with the bufferfield not allowing 16 buffer while that being the default self.donepath.write(dialog.GetPath().rstrip("\\")) * made option o default when no profile exists
def saveClick(self,event): self.update() if self v1.__options['avdump'] == '': self06 - 12.error('You must specify the path to avdump02.exe!') elif self.__options['avdump'] == 'avdump.exe': self.info('You should set the _absolute_ path to avdump.exe.\nOtherwise complications might arise.') else:2008 self * Avdump 0.Show(False)33 added
def cancelClick(self,event): self v1.05 - 13.11.refresh()2007 self.Show(False) * thx to rar for fixing dumping of files with characters in non local codepage
def onclose(self,event): v1.04 - 10.11.2007 * fix for not being able to dump files with Japanese characters in the filename self * Avdump 0.Show(False)32 added and changes implemented
def refresh(self): self v1.read_config() self03 - 13.get_checkboxes(self05.__options['misc'])2007 self.filepath.Clear() * added the console again self.filepath.write(self.__options['avdump'].rstrip('"').lstrip('"')) self.username.Clear() self.username.write(self.__options['user']) self.password.Clear() self.password.write(self.__options['pass']) self.extention.Clear() self.extention.write(self.__options['ext']) self.buffersize.Clear() self.buffersize.write(self.__options['bsize']) self.portnumber.Clear() self.portnumber.write(self.__options['port']) self.timeout.Clear() self.timeout.write(self.__options['tout']) self.retries.Clear() self.retries.write(self.__options['retries']) self.exppath.Clear() self.exppath.write(self.__options['exp'].rstrip('"').lstrip('"')) self.logpath.Clear() self.logpath.write(self.__options[' * fix for log'].rstrip('"').lstrip('"')) self.donepath.Clear() self.donepath.write(self.__options['done'].rstrip('"').lstrip('"')) self.ext.SetValue(self.__box['ext']) self.log.SetValue(self.__box['log']) self.exp.SetValue(self.__box['exp']) self.port.SetValue(self.__box['port']) self.done.SetValue(self.__box['done']) self.bsize.SetValue(self.__box['bsize']) self.tout.SetValue(self.__box['tout']) self.recursive.SetValue(self.__box['c']) self.monitor.SetValue(self.__box['m']) self.mp3.SetValue(self.__box['9']) self.pause.SetValue(self.__box['p']) self.random.SetValue(self.__box['r']) self.delete.SetValue(self.__box['z']) self.wait.SetValue(self.__box['o'])  def update(self): self.__options['avdump'] = '"' + self.filepath.GetValue() + '"' self.__options['user'] = self.username.GetValue() self.__options['pass'] = self.password.GetValue() self.__options['ext'] = self.extention.GetValue() try: temp,temp2 = self.buffersize.GetValue().split(":") temp = int(temp) temp2 = int(temp2) '''make sure it's mod 8 export and at least 256kb'''done paths with spaces if temp < 256: temp = 256 if not temp % 8: temp = temp - (temp%8) '''make sure * added parents for the dialogues so they die with the buffernumber is between 1 program and 8''can't stay open any more if temp2 > 8 or temp2 <1: temp2 = 1 temp = ("%s:%s") %(temp, temp2) except: temp = "2048:1" self.__options['bsize'] = unicode(temp) try: int(self.portnumber.GetValue()) self.__options['port'] = self.portnumber.GetValue() except: self.__options['port'] = '' self.__options['tout'] = self.timeout.GetValue() temp = int(self.timeout.GetValue()) '''make sure it's at least 20''' try: if int(temp) < 20: temp = 20 except: temp = 30 self.__options['tout'] = unicode(temp) try: int(self.retries.GetValue()) self.__options['retries'] = self.retries.GetValue() except: self.__options['retries'] = 6 self.__options['exp'] = '"' + self.exppath.GetValue() + '"' self.__options['log'] = '"' + self.logpath.GetValue() + '"' self.__options['done'] = '"' + self.donepath.GetValue() + '"' self.__box['ext'] = self.ext.GetValue() self.__box['log'] = self.log.GetValue() self.__box['exp'] = self.exp.GetValue() self.__box['port'] = self.port.GetValue() self.__box['done'] = self.done.GetValue() self.__box['bsize'] = self.bsize.GetValue * option 9 added () self.__box['tout'] = self.tout.GetValue() self.__box['c'] = self.recursive.GetValue() self.__box['m'] = self.monitor.GetValue() self.__box['9'] = self.experimental mp3.GetValue(hashing for ostdb) self.__box['p'] = self.pause.GetValue() self v1.__box['r'] = self.random.GetValue() self02 - 13.__box['z'] = self05.delete.GetValue()2007 self.__box['o'] = self.wait.GetValue() self.set_misc() self.write_config()  def * added error(self,text): message = wx.MessageDialog(self,text,style=wx.ICON_ERROR | wx.OK) message.ShowModal()  def info(self,text): message = wx.MessageDialog(self,text,style=wx.ICON_INFORMATION | wx.OK) message.ShowModal() class App(wx.App): def OnInit(self): frame = mainFrame(None, 'App') frame.Show(True) self.SetTopWindow(frame) return True if __name__ == '__main__': app = App(True) app.MainLoop()and warning dialogue boxes to prevent a couple problems</pre> <pre style="font-size: 60%;">import subprocessfrom subprocess import call, PIPE, STDOUT, list2cmdline, mswindows, STARTF_USESTDHANDLESimport ctypesimport ctypes.wintypesCreateProcessW = ctypes.windll.kernel32.CreateProcessWCloseHandle = ctypes.windll.kernel32.CloseHandle __all__ = ["Popen", "PIPE", "STDOUT", "call"] class STARTUPINFOW(ctypes.Structure): _fields_ = (("cb", ctypes.wintypes.DWORD), # should init to 17*4 maybe? ("lpReserved", ctypes.wintypes.LPWSTR), ("lpDesktop", ctypes.wintypes.LPWSTR), ("lpTitle", ctypes.wintypes.LPWSTR), ("dwX", ctypes.wintypes.DWORD), ("dwY", ctypes.wintypes.DWORD), ("dwXSize", ctypes.wintypes.DWORD), ("dwYSize", ctypes.wintypes.DWORD), ("dwXCountChars", ctypes.wintypes.DWORD), ("dwYCountChars", ctypes.wintypes.DWORD), ("dwFillAttribute", ctypes.wintypes.DWORD), ("dwFlags", ctypes.wintypes.DWORD), ("wShowWindow", ctypes.wintypes.WORD), ("cbReserved2", ctypes.wintypes.WORD), ("lpReserved2", ctypes.wintypes.LPSTR), # actually LPBYTE ("hStdInput", ctypes.wintypes.HANDLE), ("hStdOutput", ctypes.wintypes.HANDLE), ("hStdError", ctypes.wintypes.HANDLE)) class PROCESS_INFORMATION(ctypes.Structure): _fields_ = (("hProcess", ctypes.wintypes.HANDLE), ("hThread", ctypes.wintypes.HANDLE), ("dwProcessId", ctypes.wintypes.DWORD), ("dwThreadId", ctypes.wintypes.DWORD)) class Popen(subprocess.Popen): """def __init__(self, args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0): print "BOOM" subprocess.Popen.__init__(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags)""" if mswindows: def _execute_child(self, args, executable, preexec_fn, close_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite):  if not isinstance(args, basestring): args = list2cmdline(args) if not isinstance(args, unicode): subprocess.Popen._execute_child(self, args, executable, preexec_fn, close_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite) return  default_startupinfo = STARTUPINFOW() if startupinfo == None: startupinfo = default_startupinfo else: raise NotImplementedError("Can't pass startup stuff") if not None in (p2cread, c2pwrite, errwrite): raise NotImplementedError("Can't pass file object bits") startupinfo.dwFlags |= STARTF_USESTDHANDLES startupinfo.hStdInput = p2cread #.Detatch() startupinfo.hStdOutput = c2pwrite startupinfo.hStdError = errwrite  if shell: raise NotImplementedError("Can't pick your own shell added some exception handling for unicode args")a few fields margs = ctypes v1.create_unicode_buffer(args) processinfo = PROCESS_INFORMATION()  CreateProcessW(executable, margs, None, None, 1, creationflags, env, cwd, ctypes.byref(startupinfo), ctypes.byref(processinfo)) hp, ht, pid, tid = (processinfo01 - 12.hProcess, processinfo05.hThread,2007 processinfo.dwProcessId, processinfo.dwThreadId) # can't wrap this as * killed a _subprocess_handle so scuppered, need sp_handle_new()nasty bug with trailing \ in the scanpath self._handle = hp self v1.pid = pid CloseHandle(ht) # ht00 - 12.Close()  if p2cread != None: p2cread05.Close()2007 if c2pwrite != None: c2pwrite.Close() if errwrite != None: errwrite.Close() * Initial release
</pre>
[[Category:Features]]
[[Category:AniDB Clients]]
[[Category:Avdump]]
[[Category:Development]]

Navigation menu

MediaWiki spam blocked by CleanTalk.