Difference between revisions of "Avdump GUI"

From AniDB
Jump to navigation Jump to search
Line 13: Line 13:
 
==Changelog==
 
==Changelog==
 
<pre>
 
<pre>
 +
v2.00 - 03.06.2011
 +
Avdump2 Build 4260 added
 +
rewrote the whole lot and simplified it
 +
 
  v1.07 - 06.04.2008
 
  v1.07 - 06.04.2008
 
  Avdump 0.34 added
 
  Avdump 0.34 added
Line 49: Line 53:
  
 
<pre  style="font-size: 60%;">
 
<pre  style="font-size: 60%;">
import wx,os,subprocessw,sys
+
import sys, os, platform, subprocessw, ConfigParser, string, unicodedata
 +
 
 +
from time import time
 +
 
 +
# Import Qt modules
 +
from PyQt4 import QtCore, QtGui
 +
 
 +
# Import the compiled UI module
 +
from gui import Ui_MainWindow
 +
 
 +
# Create a class for our main window
 +
class Main(QtGui.QMainWindow):
 +
    def __init__(self):
 +
        QtGui.QMainWindow.__init__(self)
 +
        self._ui = Ui_MainWindow()
 +
        self._ui.setupUi(self)
 +
        self._filelist = {}
 +
        self._paths = {}
 +
        self._done_files = []
 +
        self._worker = None
 +
        self._export_filename = 'exports/export_' + str(int(time())) + '.txt'
 +
        self._allowed_extensions = ('avi', 'mpg', 'mpeg', 'ts', 'm2ts', 'rm', 'rmvb', 'asf', 'wmv', 'mov', 'qt', 'ogm',
 +
                                  'mp4', 'mkv', 'swf', 'flv', 'ogv', 'webm', 'mk3d', 'srt', 'sub', 'ssa', 'smi', 'idx', 'ass',
 +
                                  'txt', 'mks', 'lrc', 'rt', 'tmp', 'js', 'pjs', 'tts', 'xss', 'mp3', 'aac', 'ac3', 'dts', 'wav',
 +
                                  'flac', 'wma', 'mka', 'ra', 'ogg', 'm4a', 'dtshd', 'thd', 'rar', 'zip', 'ace', '7z', 'smil')
 +
 
 +
        tmp = []
 +
        for ext in self._allowed_extensions:
 +
            tmp.append('*.' + ext)
 +
 
 +
        self._allowed_extensions_str = "; ".join(tmp)
 +
 
 +
        self._ui.datatable.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
 +
        self._ui.datatable.setColumnWidth(0, 90)
 +
        self._ui.datatable.setColumnWidth(1, 250)
 +
        self._ui.datatable.setColumnWidth(2, 40)
 +
 
 +
        self.connect(self._ui.files_button, QtCore.SIGNAL("clicked()"), self._slotFile)
 +
        self.connect(self._ui.folder_button, QtCore.SIGNAL("clicked()"), self._slotFolder)
 +
        self.connect(self._ui.start_button, QtCore.SIGNAL("clicked()"), self._run)
 +
        self.connect(self._ui.stop_button, QtCore.SIGNAL("clicked()"), self._stop)
 +
        self.connect(QtGui.QAction(self), QtCore.SIGNAL('triggered()'), QtCore.SLOT('close()'))
 +
 
 +
        self._enable_elements()
 +
        self._read_config()
 +
        self._read_done()
 +
 
 +
#################################################
 +
#                                              #
 +
#                GUI FUNCTIONS                #
 +
#                                              #
 +
#################################################
 +
 
 +
    def _disable_elements(self):
 +
        self._ui.username.setDisabled(True)
 +
        self._ui.apikey.setDisabled(True)
 +
        self._ui.files_button.setDisabled(True)
 +
        self._ui.folder_button.setDisabled(True)
 +
        self._ui.done.setDisabled(True)
 +
        self._ui.exp.setDisabled(True)
 +
        self._ui.start_button.setDisabled(True)
 +
        self._ui.stop_button.setEnabled(True)
 +
 
 +
    def _enable_elements(self):
 +
        self._ui.username.setEnabled(True)
 +
        self._ui.apikey.setEnabled(True)
 +
        self._ui.files_button.setEnabled(True)
 +
        self._ui.folder_button.setEnabled(True)
 +
        self._ui.done.setEnabled(True)
 +
        self._ui.exp.setEnabled(True)
 +
        self._ui.start_button.setEnabled(True)
 +
        self._ui.stop_button.setDisabled(True)
 +
 
 +
    def _output_export(self):
 +
        self._ui.ed2k_export.setText("".join(file(self._export_filename).readlines()))
 +
 
 +
    def _calculate_progress(self):
 +
        if self._ui.datatable.rowCount() == 0:
 +
            return 0
 +
 
 +
        done = 0
 +
        for i in range(self._ui.datatable.rowCount()):
 +
            if unicode(self._ui.datatable.item(i,2).text()) == 'done':
 +
                done += 1
 +
 
 +
        return done*100/self._ui.datatable.rowCount()
 +
 
 +
#################################################
 +
#                                              #
 +
#                EVENT HANDLER                #
 +
#                                              #
 +
#################################################
 +
    def _closeEvent(self,event):
 +
        self._stop()
 +
        self._write_config()
 +
        event.accept()
 +
 
 +
    def _done(self, path):
 +
        i = self._paths[path]
 +
        item = QtGui.QTableWidgetItem('done')
 +
        self._ui.datatable.setItem(i, 2, item)
 +
        if self._ui.exp.isChecked():
 +
            self._output_export()
 +
        self._ui.progressBar.setValue(self._calculate_progress())
 +
 
 +
    def _finished(self):
 +
        self._paths = {}
 +
        self._ui.progressBar.setValue(self._calculate_progress())
 +
        self._worker = None
 +
        self._enable_elements()
 +
        if self._ui.exp.isChecked():
 +
            self._output_export()
 +
 
 +
    def _stop(self):
 +
        if self._worker is not None:
 +
            self._worker.stop()
 +
            self._output_export()
 +
            self._enable_elements()
  
class mainFrame(wx.Frame):
+
    def _slotFile(self):
    __simple = ['p','z','r','m','c','o','9']
+
        files = QtGui.QFileDialog.getOpenFileNames(self, 'File select', os.getcwd(), self._allowed_extensions_str)
    __options = {'avdump':'avdump.exe','user':'','pass':'','ext':'','misc':'','bsize':'2048:16','port':'','tout':'30','retries':'6','exp':'export.txt','log':'log.txt','done':'done.txt'}
+
        for path in files:
    __configfile='config.ini'
+
            self._add_file(unicode(path))
  
     def read_config(self,newconfig=''):
+
     def _slotFolder(self):
         '''read the config file and return the content'''
+
         path = unicode(QtGui.QFileDialog.getExistingDirectory(self, "Select Directory"))
        if not os.path.exists(self.__configfile):
+
         if path != '':
            for elem in self.__options:
+
            for root, dir, files in os.walk(path):
                newconfig += ('%s=%s\n') %(elem,self.__options[elem])
+
                 for filename in files:
            file(self.__configfile,"w").write(newconfig)
+
                     self._add_file(os.path.join(root, filename))
         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
 
  
     def __init__(self, parent, title):
+
     def _add_file(self, fileloc):
         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)
+
         if len(fileloc) == 0:
        self.panel = wx.Panel(self, -1)
+
            return
         self.filepath = wx.TextCtrl(self.panel, -1, '', (95, 25), size=(190, 24))
+
         elif unicodedata.normalize('NFKC', fileloc) in self._done_files:
        self.start = wx.Button(self.panel, -1, 'Start', (90,75), (-1, -1))
+
            return
        self.options = wx.Button(self.panel, -1, 'Options', (185,75), (-1, -1))
 
        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')
 
  
    def selectClick(self, event,path=''):
+
         no = self._ui.datatable.rowCount()
         if self.scantype.GetStringSelection() == 'Files':
 
            dialog = wx.FileDialog ( self, message = 'Pick a directory.', style= wx.FD_MULTIPLE)
 
            if dialog.ShowModal() == wx.ID_OK:
 
                temp = dialog.GetPaths()
 
                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
 
  
    def startClick(self, event):
+
         if platform.system().lower() == 'windows':
         self.read_config()
+
             fileloc = fileloc.replace("/", "\\")
        self.__options['param'] = ''
+
             filepath, filename = fileloc.rsplit("\\", 1)
        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.info('You should set the _absolute_ path to avdump.exe.\nOtherwise complications might arise.')
 
 
         else:
 
         else:
             if self.__options['misc'].lstrip(',') > 0:
+
             filepath, filename = fileloc.rsplit("/", 1)
                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'] += ' -' + elem + ':' + self.__options[elem] + ':' + self.__options['retries']
 
                        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'])
 
            subprocessw.Popen(arg)
 
  
    def optionsClick(self, event):
+
        tmp, ext = filename.rsplit('.', 1)
         self.child.refresh()
+
         if ext not in self._allowed_extensions:
        self.child.Show(True)
+
            return
  
class OptionsFrame(wx.Frame):
+
        if fileloc not in self._filelist.keys():
    __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':True,'9':False}
+
            self._filelist[fileloc] = 1
    __options = {'avdump':'avdump.exe','user':'','pass':'','ext':'','misc':'','bsize':'2048:16','port':'','tout':'30','retries':'6','exp':'export.txt','log':'log.txt','done':'done.txt'}
+
            self._ui.datatable.insertRow(no)
    __configfile='config.ini'
 
  
    def read_config(self):
+
            item = QtGui.QTableWidgetItem(filepath)
        '''read the config file and return the content'''
+
             self._ui.datatable.setItem(no, 0, item)
        if not os.path.exists(self.__configfile):
 
             self.write_config()
 
        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
 
  
    def write_config(self,newconfig=''):
+
            item = QtGui.QTableWidgetItem(filename)
        for elem in self.__options:
+
             self._ui.datatable.setItem(no, 1, item)
            newconfig += ('%s=%s\n') %(elem,self.__options[elem])
 
             file(self.__configfile,"w").write(newconfig)
 
  
    def set_misc(self,misc=''):
+
            item = QtGui.QTableWidgetItem('new')
        for elem in self.__box:
+
            self._ui.datatable.setItem(no, 2, item)
             if self.__box[elem] is True:
+
             self._ui.progressBar.setValue(self._calculate_progress())
                misc += elem + ','
 
        self.__options['misc'] = misc
 
  
     def get_checkboxes(self,misc):
+
     def _run(self):
         if misc is not None:
+
         if self._ui.datatable.rowCount() == 0:
             misc = misc.rstrip(',').lstrip(',')
+
             QtGui.QMessageBox.information(self, "Error!", "No files to scan in list.", QtGui.QMessageBox.Ok)
             if misc.find(',') > 0:
+
             return
                for elem in misc.split(','):
+
        elif not os.path.exists('avdump2cl.exe'):
                    self.__box[elem] = True
+
            QtGui.QMessageBox.information(self, "Error!", "Avdump2cl.exe not found.", QtGui.QMessageBox.Ok)
             else:
+
             return
                self.__box[misc] = True
 
  
    def __init__(self, parent, title):
+
         paths    = []
         wx.Frame.__init__(self, parent, -1, 'options', wx.DefaultPosition, (301, 691), style=wx.CLOSE_BOX | wx.SYSTEM_MENU | wx.CAPTION | 0 | 0 | wx.MINIMIZE_BOX)
+
         for i in range(self._ui.datatable.rowCount()):
        self.panel = wx.Panel(self, -1)
+
            if unicode(self._ui.datatable.item(i,2).text()) == 'new':
        self.adoptions = wx.StaticBox(self.panel, -1, "advanced options", (5,170), (275, 290))
+
                path = os.path.join(unicode(self._ui.datatable.item(i,0).text()), unicode(self._ui.datatable.item(i,1).text()))
        self.groupbox3 = wx.StaticBox(self.panel, -1, "Path to Avdump", (5,0), (275, 55))
+
                paths.append(path)
        self.groupbox4 = wx.StaticBox(self.panel, -1, "UDP API Username/Password", (5,55), (275, 115))
+
                self._paths[path] = i
        self.groupbox5 = wx.StaticBox(self.panel, -1, "logs", (5,460), (275, 170))
 
        self.filepath = wx.TextCtrl(self.panel, -1, '', (15,20), size=(220, 25))
 
        self.selectavdump = wx.Button(self.panel, -1, '...', (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))
 
        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 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)
 
        self.Bind(wx.EVT_BUTTON, self.cancelClick, self.cancel)
 
        self.Bind(wx.EVT_CLOSE, self.onclose)
 
        self.refresh()
 
  
    def selectavdClick(self, event):
+
        if len(paths) > 0:
        dialog = wx.FileDialog ( self, message = 'Pick a directory.')
+
            self._ui.progressBar.setValue(self._calculate_progress())
        if dialog.ShowModal() == wx.ID_OK:
+
            self._disable_elements()
             self.filepath.Clear()
+
            username = unicode(self._ui.username.text())
             self.filepath.write(dialog.GetPath().rstrip("\\"))
+
             apikey  = unicode(self._ui.apikey.text())
 +
             done    = ''
 +
            if self._ui.done.isChecked() is True:
 +
                done = '-done:done.txt'
  
    def selectlogClick(self, event):
+
            exp      = ''
        dialog = wx.FileDialog ( self, message = 'Pick a directory.')
+
            if self._ui.exp.isChecked() is True:
        if dialog.ShowModal() == wx.ID_OK:
+
                exp  = '-exp:' + self._export_filename
             self.logpath.Clear()
+
               
             self.logpath.write(dialog.GetPath().rstrip("\\"))
+
            self._worker = avdump_worker(username, apikey, done, exp, paths)
 +
             self.connect(self._worker, QtCore.SIGNAL("done"), self._done)
 +
             self.connect(self._worker, QtCore.SIGNAL("finished"), self._finished)
 +
            self._worker.start()          
  
     def selectexpClick(self, event):
+
#################################################
         dialog = wx.FileDialog ( self, message = 'Pick a directory.')
+
#                                              #
        if dialog.ShowModal() == wx.ID_OK:
+
#              CONFIG READ/WRITE              #
            self.exppath.Clear()
+
#                                              #
             self.exppath.write(dialog.GetPath().rstrip("\\"))
+
#################################################
 +
     def _read_config(self):
 +
         if os.path.exists('options.ini'):
 +
            config = ConfigParser.ConfigParser()
 +
            config.read('options.ini')
 +
            self._ui.username.setText(config.get('DEFAULT', 'username'))
 +
            self._ui.apikey.setText(config.get('DEFAULT', 'apikey'))
 +
            if config.get('DEFAULT', 'done') == '1':
 +
                self._ui.done.setChecked(True)
 +
             else:
 +
                self._ui.done.setChecked(False)
  
    def selectdoneClick(self, event):
+
            if config.get('DEFAULT', 'exp') == '1':
        dialog = wx.FileDialog ( self, message = 'Pick a directory.')
+
                self._ui.exp.setChecked(True)
        if dialog.ShowModal() == wx.ID_OK:
+
             else:
            self.donepath.Clear()
+
                self._ui.exp.setChecked(False)
             self.donepath.write(dialog.GetPath().rstrip("\\"))
 
  
     def saveClick(self,event):
+
     def _write_config(self):
         self.update()
+
        config = ConfigParser.ConfigParser()
         if self.__options['avdump'] == '':
+
        config.set("DEFAULT", "username", str(self._ui.username.text()))
             self.error('You must specify the path to avdump.exe!')
+
         config.set("DEFAULT", "apikey", str(self._ui.apikey.text()))
         elif self.__options['avdump'] == 'avdump.exe':
+
         if self._ui.done.isChecked():
             self.info('You should set the _absolute_ path to avdump.exe.\nOtherwise complications might arise.')
+
             config.set("DEFAULT", "done", 1)
 +
        else:
 +
            config.set("DEFAULT", "done", 0)
 +
         if self._ui.exp.isChecked():
 +
             config.set("DEFAULT", "exp", 1)
 
         else:
 
         else:
             self.Show(False)
+
             config.set("DEFAULT", "exp", 0)
 +
        config.write(file("options.ini", "w"))
  
     def cancelClick(self,event):
+
     def _read_done(self):
         self.refresh()
+
         if os.path.exists("done.txt"):
        self.Show(False)
+
            for line in file("done.txt"):
 +
                self._done_files.append(unicodedata.normalize('NFKC', line.decode("utf8").strip()))
  
     def onclose(self,event):
+
class avdump_worker(QtCore.QThread):
         self.Show(False)
+
     def __init__(self, username, apikey, done, exp, paths):
 +
        QtCore.QThread.__init__(self, parent=None)
 +
        self._username    = username
 +
        self._apikey      = apikey
 +
        self._done        = done
 +
        self._exp        = exp
 +
        self._paths      = paths
 +
         self._was_stopped = False
 +
        self._avdump      = None
  
     def refresh(self):
+
     def stop(self):
         self.read_config()
+
         self._was_stopped = True
        self.get_checkboxes(self.__options['misc'])
+
         self._avdump.terminate()
        self.filepath.Clear()
 
        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['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):
+
     def run(self):
         self.__options['avdump'] = '"' + self.filepath.GetValue() + '"'
+
         for path in self._paths:
        self.__options['user'] = self.username.GetValue()
+
            if self._was_stopped is True:
        self.__options['pass'] = self.password.GetValue()
+
                break
        self.__options['ext'] = self.extention.GetValue()
+
            self._avdump = subprocessw.Popen((u'avdump2cl.exe -ac:%s:%s %s %s "%s"') %(self._username, self._apikey, self._done, self._exp, path))
        try:
+
             self._avdump.communicate()
            temp,temp2 = self.buffersize.GetValue().split(":")
+
             if self._was_stopped is False:
            temp = int(temp)
+
                self.emit(QtCore.SIGNAL('done'), path)
            temp2 = int(temp2)
 
            '''make sure it's mod 8 and at least 256kb'''
 
            if temp < 256:
 
                temp = 256
 
            if not temp % 8:
 
                temp = temp - (temp%8)
 
            '''make sure the buffernumber is between 1 and 16'''
 
            if temp2 > 16 or temp2 <1:
 
                temp2 = 1
 
            temp = ("%s:%s") %(temp, temp2)
 
        except:
 
            temp = "2048:16"
 
        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()
 
        self.__box['tout'] = self.tout.GetValue()
 
        self.__box['c'] = self.recursive.GetValue()
 
        self.__box['m'] = self.monitor.GetValue()
 
        self.__box['9'] = self.mp3.GetValue()
 
        self.__box['p'] = self.pause.GetValue()
 
        self.__box['r'] = self.random.GetValue()
 
        self.__box['z'] = self.delete.GetValue()
 
        self.__box['o'] = self.wait.GetValue()
 
        self.set_misc()
 
        self.write_config()
 
  
    def error(self,text):
+
        if self._was_stopped is False:
        message = wx.MessageDialog(self,text,style=wx.ICON_ERROR | wx.OK)
+
            self.emit(QtCore.SIGNAL('finished'))
        message.ShowModal()
 
  
    def info(self,text):
+
def main():
        message = wx.MessageDialog(self,text,style=wx.ICON_INFORMATION | wx.OK)
+
    app = QtGui.QApplication(sys.argv)
        message.ShowModal()
+
    window=Main()
       
+
    window.show()
class App(wx.App):
+
     sys.exit(app.exec_())
     def OnInit(self):
 
        frame = mainFrame(None, 'App')
 
        frame.Show(True)
 
        self.SetTopWindow(frame)
 
        return True
 
  
if __name__ == '__main__':
+
if __name__ == "__main__":
     app = App(True)
+
     main()
    app.MainLoop()
 
 
</pre>
 
</pre>
  
Line 446: Line 384:
 
if startupinfo == None:
 
if startupinfo == None:
 
startupinfo = STARTUPINFOW()
 
startupinfo = STARTUPINFOW()
 +
startupinfo.dwFlags |= subprocess._subprocess.STARTF_USESHOWWINDOW
 +
startupinfo.wShowWindow = subprocess._subprocess.SW_HIDE
 
else:
 
else:
 
raise NotImplementedError("Can't pass startup stuff")
 
raise NotImplementedError("Can't pass startup stuff")

Revision as of 13:32, 3 June 2011

Introduction

Note You have to set an API key in your profile before auto-creqing with Avdump GUI.

A simple GUI for Avdump2 is available for CLI skeptics. The GUI package includes the most recent version of Avdump2 as well.

Screenshot of the AVDump2 GUI

Usage

  1. Download the GUI here (portable).
  2. Set your AniDB user name and API password in the options menu.
    1. API password is set on your user settings page: http://anidb.net/perl-bin/animedb.pl?show=profile
    2. Under the "Account" tab, create a UDP API key; it can be anything you want. It is used for Avdump2 to connect to AniDB.
  3. Save the options.
  4. Select what you want to scan from the main menu; files or folders.
  5. Select the stuff you want to scan (... Button) (you can select multiple files at once).
  6. Click Start.

For further Assistance join IRC:anidb and bug Der Idiot.

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:
    "C:\Windows\System32\msiExec.exe" -i "C:\Directory\Where\Located\avdump-gui.msi"
  • Right click and run the .bat file as administrator.

Changelog

 v2.00 - 03.06.2011
 Avdump2 Build 4260 added
 rewrote the whole lot and simplified it

 v1.07 - 06.04.2008
 Avdump 0.34 added
 fixed a bug with the bufferfield not allowing 16 buffer while that being the default
 made option o default when no profile exists

 v1.06 - 12.02.2008
 Avdump 0.33 added

 v1.05 - 13.11.2007
 thx to rar for fixing dumping of files with characters in non local codepage

 v1.04 - 10.11.2007
 fix for not being able to dump files with Japanese characters in the filename
 Avdump 0.32 added and changes implemented

 v1.03 - 13.05.2007
 added the console again
 fix for log, export and done paths with spaces
 added parents for the dialogues so they die with the program and can't stay open any more
 option 9 added (experimental mp3 hashing for ostdb)
 
 v1.02 - 13.05.2007
 added error and warning dialogue boxes to prevent a couple problems
 added some exception handling for a few fields
 
 v1.01 - 12.05.2007
 killed a nasty bug with trailing \ in the scanpath
 
 v1.00 - 12.05.2007
 Initial release

Source

This GUI was coded purely in python using wxpython for the framework.

import sys, os, platform, subprocessw, ConfigParser, string, unicodedata

from time import time

# Import Qt modules
from PyQt4 import QtCore, QtGui

# Import the compiled UI module
from gui import Ui_MainWindow

# Create a class for our main window
class Main(QtGui.QMainWindow):
    def __init__(self):
        QtGui.QMainWindow.__init__(self)
        self._ui = Ui_MainWindow()
        self._ui.setupUi(self)
        self._filelist = {}
        self._paths = {}
        self._done_files = []
        self._worker = None
        self._export_filename = 'exports/export_' + str(int(time())) + '.txt'
        self._allowed_extensions = ('avi', 'mpg', 'mpeg', 'ts', 'm2ts', 'rm', 'rmvb', 'asf', 'wmv', 'mov', 'qt', 'ogm',
                                   'mp4', 'mkv', 'swf', 'flv', 'ogv', 'webm', 'mk3d', 'srt', 'sub', 'ssa', 'smi', 'idx', 'ass',
                                   'txt', 'mks', 'lrc', 'rt', 'tmp', 'js', 'pjs', 'tts', 'xss', 'mp3', 'aac', 'ac3', 'dts', 'wav',
                                   'flac', 'wma', 'mka', 'ra', 'ogg', 'm4a', 'dtshd', 'thd', 'rar', 'zip', 'ace', '7z', 'smil')

        tmp = []
        for ext in self._allowed_extensions:
            tmp.append('*.' + ext)

        self._allowed_extensions_str = "; ".join(tmp)

        self._ui.datatable.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
        self._ui.datatable.setColumnWidth(0, 90)
        self._ui.datatable.setColumnWidth(1, 250)
        self._ui.datatable.setColumnWidth(2, 40)

        self.connect(self._ui.files_button, QtCore.SIGNAL("clicked()"), self._slotFile)
        self.connect(self._ui.folder_button, QtCore.SIGNAL("clicked()"), self._slotFolder)
        self.connect(self._ui.start_button, QtCore.SIGNAL("clicked()"), self._run)
        self.connect(self._ui.stop_button, QtCore.SIGNAL("clicked()"), self._stop)
        self.connect(QtGui.QAction(self), QtCore.SIGNAL('triggered()'), QtCore.SLOT('close()'))

        self._enable_elements()
        self._read_config()
        self._read_done()

#################################################
#                                               #
#                 GUI FUNCTIONS                 #
#                                               #
#################################################

    def _disable_elements(self):
        self._ui.username.setDisabled(True)
        self._ui.apikey.setDisabled(True)
        self._ui.files_button.setDisabled(True)
        self._ui.folder_button.setDisabled(True)
        self._ui.done.setDisabled(True)
        self._ui.exp.setDisabled(True)
        self._ui.start_button.setDisabled(True)
        self._ui.stop_button.setEnabled(True)

    def _enable_elements(self):
        self._ui.username.setEnabled(True)
        self._ui.apikey.setEnabled(True)
        self._ui.files_button.setEnabled(True)
        self._ui.folder_button.setEnabled(True)
        self._ui.done.setEnabled(True)
        self._ui.exp.setEnabled(True)
        self._ui.start_button.setEnabled(True)
        self._ui.stop_button.setDisabled(True)

    def _output_export(self):
        self._ui.ed2k_export.setText("".join(file(self._export_filename).readlines()))

    def _calculate_progress(self):
        if self._ui.datatable.rowCount() == 0:
            return 0

        done = 0
        for i in range(self._ui.datatable.rowCount()):
            if unicode(self._ui.datatable.item(i,2).text()) == 'done':
                done += 1

        return done*100/self._ui.datatable.rowCount()

#################################################
#                                               #
#                 EVENT HANDLER                 #
#                                               #
#################################################
    def _closeEvent(self,event):
        self._stop()
        self._write_config()
        event.accept()

    def _done(self, path):
        i = self._paths[path]
        item = QtGui.QTableWidgetItem('done')
        self._ui.datatable.setItem(i, 2, item)
        if self._ui.exp.isChecked():
            self._output_export()
        self._ui.progressBar.setValue(self._calculate_progress())

    def _finished(self):
        self._paths = {}
        self._ui.progressBar.setValue(self._calculate_progress())
        self._worker = None
        self._enable_elements()
        if self._ui.exp.isChecked():
            self._output_export()

    def _stop(self):
        if self._worker is not None:
            self._worker.stop()
            self._output_export()
            self._enable_elements()

    def _slotFile(self):
        files = QtGui.QFileDialog.getOpenFileNames(self, 'File select', os.getcwd(), self._allowed_extensions_str)
        for path in files:
            self._add_file(unicode(path))

    def _slotFolder(self):
        path = unicode(QtGui.QFileDialog.getExistingDirectory(self, "Select Directory"))
        if path != '':
            for root, dir, files in os.walk(path):
                for filename in files:
                    self._add_file(os.path.join(root, filename))

    def _add_file(self, fileloc):
        if len(fileloc) == 0:
            return
        elif unicodedata.normalize('NFKC', fileloc) in self._done_files:
            return

        no = self._ui.datatable.rowCount()

        if platform.system().lower() == 'windows':
            fileloc = fileloc.replace("/", "\\")
            filepath, filename = fileloc.rsplit("\\", 1)
        else:
            filepath, filename = fileloc.rsplit("/", 1)

        tmp, ext = filename.rsplit('.', 1)
        if ext not in self._allowed_extensions:
            return

        if fileloc not in self._filelist.keys():
            self._filelist[fileloc] =  1
            self._ui.datatable.insertRow(no)

            item = QtGui.QTableWidgetItem(filepath)
            self._ui.datatable.setItem(no, 0, item)

            item = QtGui.QTableWidgetItem(filename)
            self._ui.datatable.setItem(no, 1, item)

            item = QtGui.QTableWidgetItem('new')
            self._ui.datatable.setItem(no, 2, item)
            self._ui.progressBar.setValue(self._calculate_progress())

    def _run(self):
        if self._ui.datatable.rowCount() == 0:
            QtGui.QMessageBox.information(self, "Error!", "No files to scan in list.", QtGui.QMessageBox.Ok)
            return
        elif not os.path.exists('avdump2cl.exe'):
            QtGui.QMessageBox.information(self, "Error!", "Avdump2cl.exe not found.", QtGui.QMessageBox.Ok)
            return

        paths    = []
        for i in range(self._ui.datatable.rowCount()):
            if unicode(self._ui.datatable.item(i,2).text()) == 'new':
                path = os.path.join(unicode(self._ui.datatable.item(i,0).text()), unicode(self._ui.datatable.item(i,1).text()))
                paths.append(path)
                self._paths[path] = i

        if len(paths) > 0:
            self._ui.progressBar.setValue(self._calculate_progress())
            self._disable_elements()
            username = unicode(self._ui.username.text())
            apikey   = unicode(self._ui.apikey.text())
            done     = ''
            if self._ui.done.isChecked() is True:
                done = '-done:done.txt'

            exp      = ''
            if self._ui.exp.isChecked() is True:
                exp  = '-exp:' + self._export_filename
                
            self._worker = avdump_worker(username, apikey, done, exp, paths)
            self.connect(self._worker, QtCore.SIGNAL("done"), self._done)
            self.connect(self._worker, QtCore.SIGNAL("finished"), self._finished)
            self._worker.start()           

#################################################
#                                               #
#               CONFIG READ/WRITE               #
#                                               #
#################################################
    def _read_config(self):
        if os.path.exists('options.ini'):
            config = ConfigParser.ConfigParser()
            config.read('options.ini')
            self._ui.username.setText(config.get('DEFAULT', 'username'))
            self._ui.apikey.setText(config.get('DEFAULT', 'apikey'))
            if config.get('DEFAULT', 'done') == '1':
                self._ui.done.setChecked(True)
            else:
                self._ui.done.setChecked(False)

            if config.get('DEFAULT', 'exp') == '1':
                self._ui.exp.setChecked(True)
            else:
                self._ui.exp.setChecked(False)

    def _write_config(self):
        config = ConfigParser.ConfigParser()
        config.set("DEFAULT", "username", str(self._ui.username.text()))
        config.set("DEFAULT", "apikey", str(self._ui.apikey.text()))
        if self._ui.done.isChecked():
            config.set("DEFAULT", "done", 1)
        else:
            config.set("DEFAULT", "done", 0)
        if self._ui.exp.isChecked():
            config.set("DEFAULT", "exp", 1)
        else:
            config.set("DEFAULT", "exp", 0)
        config.write(file("options.ini", "w"))

    def _read_done(self):
        if os.path.exists("done.txt"):
            for line in file("done.txt"):
                self._done_files.append(unicodedata.normalize('NFKC', line.decode("utf8").strip()))

class avdump_worker(QtCore.QThread):
    def __init__(self, username, apikey, done, exp, paths):
        QtCore.QThread.__init__(self, parent=None)
        self._username    = username
        self._apikey      = apikey
        self._done        = done
        self._exp         = exp
        self._paths       = paths
        self._was_stopped = False
        self._avdump      = None

    def stop(self):
        self._was_stopped = True
        self._avdump.terminate()

    def run(self):
        for path in self._paths:
            if self._was_stopped is True:
                break
            self._avdump = subprocessw.Popen((u'avdump2cl.exe -ac:%s:%s %s %s "%s"') %(self._username, self._apikey, self._done, self._exp, path))
            self._avdump.communicate()
            if self._was_stopped is False:
                self.emit(QtCore.SIGNAL('done'), path)

        if self._was_stopped is False:
            self.emit(QtCore.SIGNAL('finished'))

def main():
    app = QtGui.QApplication(sys.argv)
    window=Main()
    window.show()
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()

Wrapper module for subprocess by rar

import subprocess
from subprocess import call, PIPE, STDOUT, list2cmdline, mswindows
import ctypes
import ctypes.wintypes
CreateProcessW = ctypes.windll.kernel32.CreateProcessW
CloseHandle = 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))

if mswindows:
	class Popen(subprocess.Popen):
		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

			if startupinfo == None:
				startupinfo = STARTUPINFOW()
				startupinfo.dwFlags |= subprocess._subprocess.STARTF_USESHOWWINDOW
				startupinfo.wShowWindow = subprocess._subprocess.SW_HIDE
			else:
				raise NotImplementedError("Can't pass startup stuff")
			
			if not None in (p2cread, c2pwrite, errwrite):
				raise NotImplementedError("Can't pass file object bits")

			if shell:
				raise NotImplementedError("Can't pick your own shell for unicode args")
			
			margs = ctypes.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 = (processinfo.hProcess, processinfo.hThread,
				processinfo.dwProcessId, processinfo.dwThreadId)
			
			# can't wrap this as a _subprocess_handle so scuppered, need sp_handle_new()
			self._handle = hp
			self.pid = pid
			CloseHandle(ht) # ht.Close()
else:
	Popen = subprocess.Popen