影片信息提取 —— 我的第一个wxPython程序
Felix Yan | 2010-03-29 | 566 views
我的第一个在 Boa Constructor 下写的 wxPython 程序…
基本功能:
1, 输入影片名(中文/英文, 可以不输全) 输出影片信息
2, 从资源管理器拖放mkv文件到窗口, 输出影片信息+文件信息(分辨率 片长 MD5/SHA1/ed2k链接 等等)
***ChangeLog***
20100514 0.11a
增加制作par2包功能
hash可选
卡界面的事情移到子线程,多线程操作
增加制作人选择功能
完美实现跨平台兼容(WinXP/Ubuntu x64已测试)
20100329 发布第一个版本(v0.1a)
下载请移步 http://code.google.com/p/movieinfofetch/downloads/list
以下是全部代码:
#Boa:Frame:Frame1 # -*- coding: utf-8 -*- import wx import wx.richtext import urllib,hashlib import re from MediaInfoDLL import * import time import threading import thread import Queue import traceback import os import sys from xml.dom import minidom reload(sys) sys.setdefaultencoding('utf8') store='' #FileInfo store2='' #MovieInfo store3='' #CustomInfo authorname=[] file='' file2='' addone = False from wx.lib import newevent def create(parent): return Frame1(parent) [wxID_FRAME1, wxID_FRAME1BUTTON1, wxID_FRAME1BUTTON2, wxID_FRAME1BUTTON3, wxID_FRAME1BUTTON4, wxID_FRAME1CHECKBOX1, wxID_FRAME1COMBOBOX1, wxID_FRAME1PANEL1, wxID_FRAME1RICHTEXTCTRL1, wxID_FRAME1STATICTEXT1, wxID_FRAME1TEXTCTRL1, ] = [wx.NewId() for _init_ctrls in range(11)] class MyFileDropTarget(wx.FileDropTarget): def __init__(self, window): wx.FileDropTarget.__init__(self) self.window = window def OnDropFiles(self, x, y, filenames): global file #self.window.AppendText("\n%d file(s) dropped at (%d,%d):\n" % (len(filenames), x, y)) self.window.Clear() for file in filenames: self.window.AppendText(file) return class Frame1(wx.Frame): def _init_coll_flexGridSizer1_Items(self, parent): # generated method, don't edit parent.AddWindow(self.staticText1, 0, border=9, flag=wx.ADJUST_MINSIZE | wx.ALL) parent.AddWindow(self.textCtrl1, 0, border=5, flag=wx.EXPAND | wx.ALL) parent.AddWindow(self.button1, 0, border=5, flag=wx.ADJUST_MINSIZE | wx.ALL) parent.AddWindow(self.comboBox1, 1, border=5, flag=wx.EXPAND | wx.ALL) def _init_coll_flexGridSizer2_Items(self, parent): # generated method, don't edit parent.AddWindow(self.button2, 0, border=5, flag=wx.ADJUST_MINSIZE | wx.ALL) parent.AddWindow(self.button3, 0, border=5, flag=wx.ADJUST_MINSIZE | wx.ALL) parent.AddWindow(self.button4, 0, border=5, flag=wx.ADJUST_MINSIZE | wx.ALL) parent.AddWindow(self.checkBox1, 0, border=0, flag=0) def _init_coll_boxSizer1_Items(self, parent): # generated method, don't edit parent.AddSizer(self.flexGridSizer1, 0, border=0, flag=0) parent.AddWindow(self.richTextCtrl1, 1, border=7, flag=wx.EXPAND | wx.ALL) parent.AddSizer(self.flexGridSizer2, 0, border=0, flag=0) def _init_sizers(self): # generated method, don't edit self.boxSizer1 = wx.BoxSizer(orient=wx.VERTICAL) self.flexGridSizer1 = wx.FlexGridSizer(cols=0, hgap=0, rows=1, vgap=0) self.flexGridSizer2 = wx.FlexGridSizer(cols=0, hgap=0, rows=1, vgap=0) self._init_coll_boxSizer1_Items(self.boxSizer1) self._init_coll_flexGridSizer1_Items(self.flexGridSizer1) self._init_coll_flexGridSizer2_Items(self.flexGridSizer2) self.panel1.SetSizer(self.boxSizer1) def _init_ctrls(self, prnt): # generated method, don't edit wx.Frame.__init__(self, id=wxID_FRAME1, name='', parent=prnt, pos=wx.Point(535, 138), size=wx.Size(467, 481), style=wx.DEFAULT_FRAME_STYLE, title='Movie Info Fetcher v0.11a - By Felix Yan') self.SetClientSize(wx.Size(467, 481)) self.SetBackgroundColour(wx.Colour(222, 222, 222)) self.Bind(wx.EVT_CLOSE, self.OnFrame1Close) self.panel1 = wx.Panel(id=wxID_FRAME1PANEL1, name='panel1', parent=self, pos=wx.Point(0, 0), size=wx.Size(467, 481), style=wx.TAB_TRAVERSAL) self.staticText1 = wx.StaticText(id=wxID_FRAME1STATICTEXT1, label='\xc6\xac\xc3\xfb'.decode('gbk'), name='staticText1', parent=self.panel1, pos=wx.Point(9, 9), size=wx.Size(31, 13), style=0) self.textCtrl1 = wx.TextCtrl(id=wxID_FRAME1TEXTCTRL1, name='textCtrl1', parent=self.panel1, pos=wx.Point(54, 5), size=wx.Size(146, 27), style=0, value='') self.button1 = wx.Button(id=wxID_FRAME1BUTTON1, label='\xbc\xec\xcb\xf7\xd0\xc5\xcf\xa2'.decode('gbk'), name='button1', parent=self.panel1, pos=wx.Point(210, 5), size=wx.Size(75, 23), style=0) self.button1.Bind(wx.EVT_BUTTON, self.OnButton1Button, id=wxID_FRAME1BUTTON1) self.button2 = wx.Button(id=wxID_FRAME1BUTTON2, label=u'\u5236\u4f5cpar2\u5305', name='button2', parent=self.panel1, pos=wx.Point(5, 453), size=wx.Size(120, 23), style=0) self.button2.Bind(wx.EVT_BUTTON, self.OnButton2Button, id=wxID_FRAME1BUTTON2) self.richTextCtrl1 = wx.richtext.RichTextCtrl(id=wxID_FRAME1RICHTEXTCTRL1, parent=self.panel1, pos=wx.Point(7, 44), size=wx.Size(453, 397), style=wx.richtext.RE_MULTILINE, value='') self.button3 = wx.Button(id=wxID_FRAME1BUTTON3, label='\xb8\xb4\xd6\xc6\xb5\xbd\xbc\xf4\xcc\xf9\xb0\xe5'.decode('gbk'), name='button3', parent=self.panel1, pos=wx.Point(135, 453), size=wx.Size(120, 23), style=0) self.button3.Bind(wx.EVT_BUTTON, self.OnButton3Button, id=wxID_FRAME1BUTTON3) self.comboBox1 = wx.ComboBox(choices=[], id=wxID_FRAME1COMBOBOX1, name='comboBox1', parent=self.panel1, pos=wx.Point(295, 5), size=wx.Size(160, 27), style=0, value=u'') self.comboBox1.SetLabel(u'') self.comboBox1.Bind(wx.EVT_COMBOBOX, self.OnComboBox1Combobox, id=wxID_FRAME1COMBOBOX1) self.comboBox1.Bind(wx.EVT_TEXT, self.OnComboBox1Text, id=wxID_FRAME1COMBOBOX1) self.checkBox1 = wx.CheckBox(id=wxID_FRAME1CHECKBOX1, label=u'\u8ba1\u7b97Hash', name='checkBox1', parent=self.panel1, pos=wx.Point(385, 448), size=wx.Size(80, 23), style=0) self.checkBox1.SetValue(True) self.button4 = wx.Button(id=wxID_FRAME1BUTTON4, label=u'\u4fdd\u5b58\u5230\u6587\u672c\u6587\u4ef6', name='button4', parent=self.panel1, pos=wx.Point(265, 453), size=wx.Size(115, 23), style=0) self.button4.Bind(wx.EVT_BUTTON, self.OnButton4Button, id=wxID_FRAME1BUTTON4) self._init_sizers() def __init__(self, parent): self._init_ctrls(parent) dt = MyFileDropTarget(self.textCtrl1) self.richTextCtrl1.SetDropTarget(dt) self.button1.SetDefault() self.GetAuthorName() def OnButton1Button(self, event): global store global store2 global authorname if authorname.count(self.comboBox1.GetValue())>0: authorname.remove(self.comboBox1.GetValue()) if self.comboBox1.GetValue()!= '': authorname.insert(0,self.comboBox1.GetValue()) self.comboBox1.Clear() self.comboBox1.AppendItems(authorname) if len(authorname)>0: self.comboBox1.SetValue(authorname[0]) store2='' store='' self.richTextCtrl1.Clear() GetInfo(self, self.textCtrl1.GetValue()) def OnButton2Button(self, event): self.progress3 = wx.ProgressDialog("Creating...", u"正在创建par2包, 请稍候…", 100, style=wx.PD_AUTO_HIDE) self.t = TRun3(self) self.t.setDaemon(True) self.t.start() #dlg = wx.TextEntryDialog(None, u"新字段名?",u'增加自定义字段', '') #if dlg.ShowModal() == wx.ID_OK: # response1 = dlg.GetValue() # if len(response1)==3: # response1=response1[0]+' '+response1[1]+' '+response1[2] # else: # if len(response1)==2: # response1=response1[0]+u' '+response1[1] # # dlg2 = wx.TextEntryDialog(None, u"新字段内容?",u'增加自定义字段', '') # if dlg2.ShowModal() == wx.ID_OK: # response2 = dlg2.GetValue() # self.richTextCtrl1.AppendText(u'◎'+response1+u' '+response2+'\n') # dlg2.Destroy() #dlg.Destroy() #event.Skip() def OnButton3Button(self, event): setText(self.richTextCtrl1.GetValue()) event.Skip() def GetAuthorName(self): #xmlDom = minidom.Document() global authorname if not os.path.exists('authors.xml'): return from xml.etree import ElementTree root = ElementTree.parse(r"authors.xml") lst_node = root.findall('name') for node in lst_node: nodename = node.text authorname.append(nodename) self.comboBox1.Append(nodename) #for i in self.comboBox1.choices(): print i if len(authorname)>0: self.comboBox1.SetValue(authorname[0]) def onDone(self): global store,store2 self.richTextCtrl1.Clear() self.richTextCtrl1.AppendText(store2+'\n'+store) def updateProgress1(self, i): self.flag = self.progress.Update(i) def updateProgress2(self, i): self.flag = self.progress2.Update(i) def updateProgress3(self, i): self.flag = self.progress3.Update(i) def destroyProgress1(self): self.flag = self.progress.Destroy() def destroyProgress2(self): self.flag = self.progress2.Destroy() def destroyProgress3(self): self.flag = self.progress3.Destroy() def OnComboBox1Combobox(self, event): global authorname authorname.remove(self.comboBox1.GetValue()) authorname.insert(0,self.comboBox1.GetValue()) def OnComboBox1Text(self, event): global authorname if not addone: return if authorname.count(self.comboBox1.GetValue())>0: authorname.remove(self.comboBox1.GetValue()) authorname.insert(0,self.comboBox1.GetValue()) self.comboBox1.Clear() self.comboBox1.AppendItems(authorname) def OnFrame1Close(self, event): global authorname impl = minidom.getDOMImplementation() dom = impl.createDocument(None, 'authors', None) root = dom.documentElement for author in authorname: item = dom.createElement('name') text = dom.createTextNode(author) item.appendChild(text) root.appendChild(item) #f = file('./authors.xml','w') f = open('authors.xml','w') #import codecs #writer = codecs.lookup('utf-8')[3](f) f.write(dom.toxml()) f.close() exit() def OnButton4Button(self, event): content=self.richTextCtrl1.GetValue() f=open('info.txt','w') f.write(content.replace('\n','\r\n')) f.close wx.MessageBox(u'已成功保存到当前目录下的 info.txt 中!') def look4(source,item,multi='',p=u':[\|\s()]*(.+?)',ml=1): if multi!='': r = re.compile(item+p+multi) ms = r.findall(source) if len(ms)>0: ans=ms[0] r=re.compile('([\|()]+|\s\s+|\s\||\|\s)') ans=r.sub('|',ans) while ans.find('||')>-1: ans=ans.replace('||','|') if cmp(ans[-1],'|')==0: ans=ans[:-1] if ml==1: ans=ans.replace('|',u'\n ') else: ans=ans.replace('|',' / ') else: ans='' else: r = re.compile(item+p+'\|') ms = r.findall(source) if len(ms)>0: ans=ms[0] else: ans='' r = re.compile('\&\#.*?\;') ans = r.sub('',ans) return ans.strip() def GetInfo(self, value): global file,file2,store,store2 file=value file2=value store='' store2='' if (len(value)>0 and value[0]=='/') or (len(value)>3 and value[1:3]==':\\'): self.progress = wx.ProgressDialog(u"Hashing...", u"正在计算文件Hash, 请稍候…", 100, style=wx.PD_AUTO_HIDE) self.t = TRun(self) self.t.setDaemon(True) self.t.start() #self.t.join() time.sleep(0.5) file2 = file.split("\\")[-1].split("/")[-1][0:25] self.progress2 = wx.ProgressDialog(u"Searching...", u"正在获取影片信息, 请稍候…", 100, style=wx.PD_AUTO_HIDE) self.t2 = TRun2(self) self.t2.setDaemon(True) self.t2.start() else: time.sleep(0.5) self.progress2 = wx.ProgressDialog(u"Searching...", u"正在获取影片信息, 请稍候…", 100, style=wx.PD_AUTO_HIDE) self.t2 = TRun2(self) self.t2.setDaemon(True) self.t2.start() #while done<2: # time.sleep(0.2) def setText(aString): if not wx.TheClipboard.IsOpened(): clipdata = wx.TextDataObject() clipdata.SetText(aString) wx.TheClipboard.Open() wx.TheClipboard.SetData(clipdata) wx.TheClipboard.Close() pass class BoaApp1(wx.App): def OnInit(self): self.main = create(None) self.main.Show() self.SetTopWindow(self.main) return True class TRun(threading.Thread): def __init__(self, caller): threading.Thread.__init__(self) self.caller = caller self.flag = True def run(self): global file if self.caller.checkBox1.GetValue(): m1 = hashlib.md5() m2 = hashlib.sha1() md4 = hashlib.new('md4').copy ed2k = [] filename = "\\".join(file.split("\\")) f = open(filename,'rb') f1 = os.stat(file) size = f1.st_size now = 9728000 bytes = f.read(9728000) while(bytes != ''): m1.update(bytes) m2.update(bytes) m3 = md4() m3.update(bytes) ed2k.append(m3.digest()) i=now*100/size if(i>100): i=100 #self.caller.ThreadSafeDispatch(self.update, i) wx.CallAfter(self.caller.updateProgress1, i) bytes = f.read(9728000) now+=9728000 f.close() if len(ed2k)==1: ed2kvalue = ed2k[0].encode("hex") else: m3 = md4() m3.update(reduce(lambda a,d: a + d, ed2k, "")) ed2kvalue = m3.hexdigest() md5value = m1.hexdigest() sha1value = m2.hexdigest() global store,store2 MI = MediaInfo() MI.Open(file) #self.window.AppendText(file) store = '' #store2 = '' store += u"◎文件名称 "+file.split("\\")[-1].split("/")[-1]+'\n' store += u"◎文件大小 "+MI.Get(Stream.General, 0, u"FileSize/String4")+'\n' store += u"◎影片长度 "+MI.Get(Stream.General, 0, u"Duration/String3")+'\n' overallbitrate = MI.Get(Stream.General, 0, u"OverallBitRate/String") store += u"◎混合码率 "+overallbitrate+'\n' store += u"◎封装时间 "+MI.Get(Stream.General, 0, u"Encoded_Date")+'\n' store += u"◎MMG 版本 "+MI.Get(Stream.General, 0, u"Encoded_Application")+'\n' videobitrate = MI.Get(Stream.Video, 0, u"BitRate_Nominal/String") if cmp(videobitrate,overallbitrate)!=0 and videobitrate!='': store += u"◎视频码率 "+videobitrate+'\n' audiobitrate = MI.Get(Stream.Audio, 0, u"BitRate_Nominal/String") if cmp(audiobitrate,overallbitrate)!=0 and audiobitrate!='': store += u"◎音频码率 "+audiobitrate+'\n' store += u"◎视频尺寸 "+MI.Get(Stream.Video, 0, u"Width")+' x '+MI.Get(Stream.Video, 0, u"Height")+'\n' store += u"◎画面比例 "+MI.Get(Stream.Video, 0, u"DisplayAspectRatio/String")+'\n' store += u"◎帧 率 "+MI.Get(Stream.Video, 0, u"FrameRate/String")+'\n' store += u"◎数据密度 "+MI.Get(Stream.Video, 0, u"Bits-(Pixel*Frame)")+'\n' store += u"◎音轨信息 "+MI.Get(Stream.Audio, 0, u"Title") for i in range(1,MI.Count_Get(Stream.Audio)): store += " / "+MI.Get(Stream.Audio, i, u"Title") store += "\n" store += u"◎字幕信息 "+MI.Get(Stream.Text, 0, u"Title") for i in range(1,MI.Count_Get(Stream.Text)): store += " / "+MI.Get(Stream.Text, i, u"Title") store += "\n" store += u"◎片源采用 [b]"+MI.Get(Stream.Video, 0, u"Title")+'[/b]\n' store += u"◎X264版本 "+MI.Get(Stream.Video, 0, u"Encoded_Library/Version")+'\n' store += u"◎X264参数 "+MI.Get(Stream.Video, 0, u"Encoded_Library_Settings")+"\n\n" if self.caller.checkBox1.GetValue(): store += u"◎检验MD5: "+md5value.upper()+'\n' store += u"◎检验SHA1: "+sha1value.upper()+'\n' #f = os.stat(file) #size = f.st_size store += u"\n[emule]ed2k://|file|"+file.split("\\")[-1].split("/")[-1]+"|"+"%d"%size+"|"+ed2kvalue.upper()+'|/[/emule]\n' #store2 += "[b]"+'.'.join(file.split("\\")[-1].split('.')[:-1])+"[/b]\n" #thread.start_new_thread(GetInfo,(self.caller,file.split("\\")[-1].split("/")[-1][0:25])) #file = file.split("\\")[-1].split("/")[-1][0:25] wx.CallAfter(self.caller.onDone) wx.CallAfter(self.caller.destroyProgress1) #for i in range(100): # print 'run %d' % (i+1) # self.caller.ThreadSafeDispatch(self.update, i) # if not self.flag: # self.destroy() # #print 'flag', self.flag # return # time.sleep(0.1) class TRun2(threading.Thread): def __init__(self, caller): threading.Thread.__init__(self) self.caller = caller self.flag = True def run(self): global file2 global store global store2 global authorname store2 = '' imdb = file2 r = re.compile('tt\d{5,}') ms = r.findall(imdb) goon = 1 if len(ms)>0: imdb = ms[0] wx.CallAfter(self.caller.updateProgress2, 50) goon = 0 if goon and imdb[0:4]=='http': webdata = urllib.urlopen(imdb).read() r=re.compile('tt\d{5,}') ms = r.findall(webdata) if len(ms)>0: imdb = ms[0] wx.CallAfter(self.caller.updateProgress2, 50) goon = 0 if goon: key=imdb.replace(" ","+") key=urllib.quote(key.encode('utf-8')) wx.CallAfter(self.caller.updateProgress2, 20) #wx.MessageBox(key) #webdata = unicode(urllib.urlopen("http://www.verycd.com/search/folders/"+key).read(),'utf-8') #r=re.compile('http://www\.verycd\.com/topics/\d+') webdata = unicode(urllib.urlopen("http://movie.douban.com/subject_search?search_text="+key+"&cat=1002").read(),'utf-8') r=re.compile("http://movie\.douban\.com/subject/\d+") ms = r.findall(webdata) if len(ms)>0: webdata = unicode(urllib.urlopen(ms[0]).read(),'utf-8') r=re.compile('tt\d{5,}') ms = r.findall(webdata) if len(ms)>0: imdb = ms[0] wx.CallAfter(self.caller.updateProgress2, 50) goon = 0 store2 += u'◎制 作 ' if len(authorname)>0: store2 += authorname[0] if not goon: webdata = unicode(urllib.urlopen("http://www.7176.com/title/"+imdb).read(), 'gbk') webdata = webdata.replace('\n','') r = re.compile('\<.+?\>') webdata = r.sub('\r',webdata) webdata = webdata.replace('\r','|') #webdata = webdata.replace('\n\r','\r') name=look4(webdata,u'中文名') engname=look4(webdata,u'外文别名') #wx.MessageBox('|'+engname+'|') if engname=='': engname=look4(webdata,u'片.*?名') else: r=re.compile('\(.*?\)') engname=r.sub('',engname).strip() store2 += u'◎英 文 名 '+engname+'\n' store2 += u'◎中 文 名 '+name+'\n' store2 += u'◎导 演 '+look4(webdata,u'导.*?演')+'\n' store2 += u'◎主 演 '+look4(webdata,u'主.*?演',u'上.*?映')+'\n' store2 += u'◎年 代 '+look4(webdata,u'上.*?映')+'\n' store2 += u'◎国 家 '+look4(webdata,u'地.*?区')+'\n' store2 += u'◎语 言 '+look4(webdata,u'对.*?白')+'\n' store2 += u'◎IMDb评分 '+look4(webdata,u'IMDb评分',p='[\|\s()]*(\d\.\d.*?)')+'\n' store2 += u'◎IMDb链接 http://www.imdb.com/title/'+imdb+'/\n' store2 += u'◎片 长 '+look4(webdata,u'时.*?长',p=':[\|\s()]*(\d+).*?')+' mins\n' store2 += u'◎类 别 '+look4(webdata,u'类.*?型',multi=u'分.*?级',ml=0)+'\n' wx.CallAfter(self.caller.updateProgress2, 100) if not goon: #wx.MessageBox(u'·'+name.replace('(','\(').replace(')','\)')+u'海报:') jianjie=look4(webdata,u'·剧情介绍',u'·'+name.replace('(','\(').replace(')','\)')+u'海报:','[\|\s()]*(.+?)') jianjie=jianjie.replace(' ',' ') jianjie=jianjie.replace(u' ',' ') while jianjie.find(' ')>-1: jianjie=jianjie.replace(' ',' ') jianjie=jianjie.replace('\n ','\n') jianjie=jianjie.replace(' \n','\n') jianjie=jianjie.replace('\r','') jianjie=jianjie.replace('\n\n','\n') jianjie=jianjie.replace('\n','<br>') jianjie=jianjie.replace('<br>',u"\n\n ") if jianjie!='': if jianjie[0]==' ': jianjie = jianjie[1:] jianjie=u' '+jianjie store2 += u'\n◎简 介 \n'+jianjie+'\n' wx.CallAfter(self.caller.onDone) #self.caller.t.join() #while(self.caller.t.isAlive()): self.caller.t.join() #if store!='': self.caller.richTextCtrl1.AppendText('\n'+store) #if store2!='': self.caller.richTextCtrl1.AppendText('\n'+store2) #self.AppendText(webdata) #d:ffmpeg\ffmpeg -map 0:2 -i a.mkv -f wav -ac 2 - | d:sox\sox --ignore-length --norm - -2 -t wav - | d:neroaacenc\neroAacEnc.exe -ignorelength -q 0.25 -if - -of v:\a.aac wx.CallAfter(self.caller.destroyProgress2) class TRun3(threading.Thread): def __init__(self, caller): threading.Thread.__init__(self) self.caller = caller self.flag = True def run(self): global file #store='' #store2='' ans='' if file=='': return arg='par2 c -r3 \"'+file.encode(sys.getfilesystemencoding())+'.par2\" \"'+file.encode(sys.getfilesystemencoding())+'\"' import subprocess p = subprocess.Popen(args=arg,stdout=subprocess.PIPE, shell=True) r1 = re.compile('Constructing[:\s]*([\d\.]+)%') r2 = re.compile('Processing[:\s]*([\d\.]+)%') r1yes = False while p.poll()==None: ans+=p.stdout.read(100) if not r1yes: k = r1.findall(ans) k2 = r2.findall(ans) if len(k2)>0: r1yes = True time.sleep(0.3) else: k = r2.findall(ans) if len(k)>0: #store = k[-1] #store=ans wx.CallAfter(self.caller.updateProgress3, int(float(k[-1]))) time.sleep(0.01) ans='' arg='7za a \"'+file.encode(sys.getfilesystemencoding())+'.par2.7z\" \"'+file.encode(sys.getfilesystemencoding())+'*par2\"' #global store p = subprocess.Popen(args=arg, stdout=subprocess.PIPE, shell=True) p.wait() time.sleep(0.3) #file.split("\\") if cmp(sys.platform[:3],'win')==0: arg='del '+file.encode(sys.getfilesystemencoding())+'*par2' else: arg='rm -f '+file.encode(sys.getfilesystemencoding())+'*par2' p = subprocess.Popen(args=arg, stdout=subprocess.PIPE, shell=True) p.wait() wx.CallAfter(self.caller.destroyProgress3) def main(): application = BoaApp1(0) application.MainLoop() if __name__ == '__main__': main()




到了http://code.google.com/p/movieinfofetch/downloads/list,下载哪一个文件呢?
I could remark Work and struggle and never accept an evil that you can change. or potentially Each problem that I solved became a rule which served afterwards to solve other problems.
哦,可以显示的,就是有些慢了,为什么一定要mkv格式呢,不知博主能否解释下~还有就是能不能再显示影片的图片啊,就像豆瓣网的条目一样都有个缩略图的
1, 图片是可以提取的 只是我现在还没想好设计一个怎样的UI显示。。
2, 信息提取我是用的mediainfo插件,理论上它支持的应该都可以吧。。
其实再提取个影片介绍也不错啊,可以到豆瓣或时光网或者别的地方提取,期待更新啊~
影片介绍现在是从imdb中文那个网页直接提取的,如果再增加提取点肯定会造成提取时间变长。。。我可能会考虑做一个列表供选:)
对,有人需要有人不需要嘛~
“从资源管理器拖放mkv文件到窗口”,为什么一拖就未响应呢?
这个是在计算MD5等文件信息:)
牛,但我竟然不知道哪里用的 – -
对影视发布组很有用的:)
很久没见你更新了,这个要支持
谢谢支持:)
围观
青蛙你怎么这么快…
我在刷推。。。
你看看你代码。。。等号两边都没有空格的。。。
=.=有些有 我不习惯加空格…现在在努力习惯…
囧, 您换什么库了呢?