1# -*- coding: utf-8 -*-
2# vi:si:et:sw=2:sts=2:ts=2
3
4import os
5from os.path import basename
6import time
7from addSubtitlesDialog import addSubtitlesPropertiesDialog, SubtitlesList
8
9import wx
10
11import theoraenc
12
13class AddVideoDialog(wx.Dialog):
14  def __init__(
15          self, parent, ID, title, hasKate, hasIconv,
16          size=wx.DefaultSize, pos=wx.DefaultPosition,
17          style=wx.DEFAULT_DIALOG_STYLE,
18          ):
19
20    self.videoFile = ''
21    self.hasKate = hasKate
22    self.hasIconv = hasIconv
23
24    pre = wx.PreDialog()
25    #pre.SetExtraStyle(wx.DIALOG_EX_CONTEXTHELP)
26    pre.Create(parent, ID, title, pos, size, style)
27    self.PostCreate(pre)
28
29    # Now continue with the normal construction of the dialog
30    padding = 4
31    section_padding=60
32
33    mainBox = wx.BoxSizer(wx.VERTICAL)
34    hbox = wx.BoxSizer(wx.HORIZONTAL)
35    mainBox.Add(hbox)
36    hbox.AddSpacer((8, 8))
37
38    #Video File
39    hbox = wx.BoxSizer(wx.HORIZONTAL)
40    mainBox.Add(hbox)
41    hbox.Add(wx.StaticText(self, -1, "Video File"), 0, wx.EXPAND|wx.ALL, 16)
42
43    self.btnVideoFile = wx.Button(self, size=(380, -1))
44    self.btnVideoFile.SetLabel('Select...')
45    self.Bind(wx.EVT_BUTTON, self.OnClickVideoFile, self.btnVideoFile)
46    hbox.Add(self.btnVideoFile, 0, wx.EXPAND|wx.ALL, padding)
47
48    #Quality
49    hbox = wx.BoxSizer(wx.HORIZONTAL)
50    mainBox.Add(hbox)
51
52    label = wx.StaticText(self, -1, "Video")
53    hbox.AddSpacer((12, 10))
54    hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding)
55    hbox = wx.BoxSizer(wx.HORIZONTAL)
56    mainBox.Add(hbox)
57    hbox.AddSpacer((section_padding, 10))
58
59    label = wx.StaticText(self, -1, "Quality:")
60    hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding)
61    self.videoquality = wx.TextCtrl(self, -1, '5.0', size=(32,-1))
62    hbox.Add(self.videoquality, 0, wx.EXPAND|wx.ALL, padding)
63    label = wx.StaticText(self, -1, "Bitrate (kbps):")
64    hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding)
65    self.videobitrate = wx.TextCtrl(self, -1, '', size=(65,-1))
66    hbox.Add(self.videobitrate, 0, wx.EXPAND|wx.ALL, padding)
67    hbox = wx.BoxSizer(wx.HORIZONTAL)
68    mainBox.Add(hbox)
69    hbox.AddSpacer((section_padding, 10))
70
71    #Size
72    box=45
73    label = wx.StaticText(self, -1, "Size:")
74    hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding)
75    self.width = wx.TextCtrl(self, -1, '', size=(65,-1))
76    hbox.Add(self.width, 0, wx.EXPAND|wx.ALL, padding)
77    label = wx.StaticText(self, -1, "x")
78    hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding)
79    self.height = wx.TextCtrl(self, -1, '', size=(65,-1))
80    hbox.Add(self.height, 0, wx.EXPAND|wx.ALL, padding)
81
82    #Framerate
83    label = wx.StaticText(self, -1, "Framerate:")
84    hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding)
85    self.framerate = wx.TextCtrl(self, -1, '', size=(40,-1))
86    hbox.Add(self.framerate, 0, wx.EXPAND|wx.ALL, padding)
87
88    #Crop
89    box=35
90    hbox = wx.BoxSizer(wx.HORIZONTAL)
91    mainBox.Add(hbox)
92    hbox.AddSpacer((section_padding, 10))
93    label = wx.StaticText(self, -1, "Crop:")
94    hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding)
95
96    label = wx.StaticText(self, -1, "Top")
97    hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding)
98    self.cropTop = wx.TextCtrl(self, -1, '', size=(box,-1))
99    hbox.Add(self.cropTop, 0, wx.EXPAND|wx.ALL, padding)
100
101    label = wx.StaticText(self, -1, "Left")
102    hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding)
103    self.cropLeft = wx.TextCtrl(self, -1, '', size=(box,-1))
104    hbox.Add(self.cropLeft, 0, wx.EXPAND|wx.ALL, padding)
105
106    label = wx.StaticText(self, -1, "Bottom")
107    hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding)
108    self.cropBottom = wx.TextCtrl(self, -1, '', size=(box,-1))
109    hbox.Add(self.cropBottom, 0, wx.EXPAND|wx.ALL, padding)
110
111    label = wx.StaticText(self, -1, "Right")
112    hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding)
113    self.cropRight = wx.TextCtrl(self, -1, '', size=(box,-1))
114    hbox.Add(self.cropRight, 0, wx.EXPAND|wx.ALL, padding)
115
116    box=45
117
118    hbox = wx.BoxSizer(wx.HORIZONTAL)
119    mainBox.Add(hbox)
120    label = wx.StaticText(self, -1, "Audio")
121    hbox.AddSpacer((12, 10))
122    hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding)
123
124    #Quality & Bitrate
125    hbox = wx.BoxSizer(wx.HORIZONTAL)
126    mainBox.Add(hbox)
127    hbox.AddSpacer((section_padding, 10))
128    label = wx.StaticText(self, -1, "Quality:")
129    hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding)
130    self.audioquality = wx.TextCtrl(self, -1, '1.0', size=(32,-1))
131    hbox.Add(self.audioquality, 0, wx.EXPAND|wx.ALL, padding)
132
133    label = wx.StaticText(self, -1, "Bitrate (kbps):")
134    hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding)
135    self.audiobitrate = wx.TextCtrl(self, -1, '', size=(box,-1))
136    hbox.Add(self.audiobitrate, 0, wx.EXPAND|wx.ALL, padding)
137
138    #Samplerate / Channels
139    hbox = wx.BoxSizer(wx.HORIZONTAL)
140    mainBox.Add(hbox)
141    hbox.AddSpacer((section_padding, 10))
142    label = wx.StaticText(self, -1, "Samplerate (Hz)")
143    hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding)
144    self.samplerate = wx.TextCtrl(self, -1, '', size=(56,-1))
145    hbox.Add(self.samplerate, 0, wx.EXPAND|wx.ALL, padding)
146    label = wx.StaticText(self, -1, "Channels")
147    hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding)
148    self.channels = wx.TextCtrl(self, -1, '', size=(24,-1))
149    hbox.Add(self.channels, 0, wx.EXPAND|wx.ALL, padding)
150
151    hbox = wx.BoxSizer(wx.HORIZONTAL)
152    mainBox.Add(hbox)
153
154    # subtitles ('add' button and list)
155    hbox = wx.BoxSizer(wx.HORIZONTAL)
156    mainBox.Add(hbox)
157    label = wx.StaticText(self, -1, "Subtitles")
158    hbox.AddSpacer((12, 10))
159    hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding)
160
161    hbox = wx.BoxSizer(wx.HORIZONTAL)
162    mainBox.Add(hbox)
163
164    hbox.AddSpacer((section_padding, 10))
165
166    if hasKate:
167      vbox = wx.BoxSizer(wx.VERTICAL)
168      hbox.Add(vbox)
169
170      subtitlesButtons_hbox = wx.BoxSizer(wx.HORIZONTAL)
171      vbox.Add(subtitlesButtons_hbox)
172
173      self.btnSubtitlesAdd = wx.Button(self, size=(120, -1))
174      self.btnSubtitlesAdd.SetLabel('Add...')
175      self.Bind(wx.EVT_BUTTON, self.OnClickSubtitlesAdd, self.btnSubtitlesAdd)
176      subtitlesButtons_hbox.Add(self.btnSubtitlesAdd, 0, wx.EXPAND|wx.ALL, padding)
177
178      self.btnSubtitlesRemove = wx.Button(self, size=(120, -1))
179      self.btnSubtitlesRemove.SetLabel('Remove')
180      self.Bind(wx.EVT_BUTTON, self.OnClickSubtitlesRemove, self.btnSubtitlesRemove)
181      self.btnSubtitlesRemove.Disable()
182      subtitlesButtons_hbox.Add(self.btnSubtitlesRemove, 0, wx.EXPAND|wx.ALL, padding)
183
184      self.btnSubtitlesProperties = wx.Button(self, size=(120, -1))
185      self.btnSubtitlesProperties.SetLabel('Properties')
186      self.Bind(wx.EVT_BUTTON, self.OnClickSubtitlesProperties, self.btnSubtitlesProperties)
187      self.btnSubtitlesProperties.Disable()
188      subtitlesButtons_hbox.Add(self.btnSubtitlesProperties, 0, wx.EXPAND|wx.ALL, padding)
189
190      #self.subtitles = wx.ListCtrl(self, -1, style=wx.LC_REPORT)
191      self.subtitles = SubtitlesList(self)
192      self.subtitles.Bind(wx.EVT_LIST_ITEM_SELECTED, self.CheckSubtitlesSelection)
193      self.subtitles.Bind(wx.EVT_LEFT_DCLICK, self.OnClickSubtitlesProperties)
194      self.subtitles.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.CheckSubtitlesSelection)
195      self.subtitles.Bind(wx.EVT_KILL_FOCUS, self.CheckSubtitlesSelection)
196      vbox.Add(self.subtitles, 0, wx.EXPAND|wx.ALL, padding)
197
198    else:
199      self.subtitles = None
200      hbox.Add(wx.StaticText(self, -1, "ffmpeg2theora doesn't seem to be built with subtitles support.\nSee documentation for how to enable subtitles.\n"))
201
202    '''
203    #Metadata
204    label = wx.StaticText(self, -1, "Metadata")
205    hbox.AddSpacer((12, 10))
206    hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding)
207
208    mbox=180
209    hbox = wx.BoxSizer(wx.HORIZONTAL)
210    mainBox.Add(hbox)
211    labels = wx.BoxSizer(wx.VERTICAL)
212    inputs = wx.BoxSizer(wx.VERTICAL)
213    hbox.AddSpacer((section_padding, 10))
214    hbox.Add(labels, 0, wx.ALIGN_RIGHT|wx.EXPAND|wx.ALL)
215    hbox.Add(inputs,0, wx.ALIGN_LEFT|wx.EXPAND|wx.ALL)
216
217    #Title
218    label = wx.StaticText(self, -1, "Title")
219    labels.Add(label, 0, wx.EXPAND|wx.ALL, padding)
220    self.title = wx.TextCtrl(self, -1, '', size=(mbox,-1))
221    inputs.Add(self.title, 0, wx.EXPAND|wx.ALL)
222
223    #Artist
224    label = wx.StaticText(self, -1, "Artist")
225    labels.Add(label, 0, wx.EXPAND|wx.ALL, padding)
226    self.artist = wx.TextCtrl(self, -1, '', size=(mbox,-1))
227    inputs.Add(self.artist, 0, wx.EXPAND|wx.ALL)
228
229    #date
230    label = wx.StaticText(self, -1, "Date", size=(mbox,-1))
231    labels.Add(label, 0, wx.EXPAND|wx.ALL, padding)
232    self.date = wx.TextCtrl(self, -1, '', size=(mbox,-1))
233    inputs.Add(self.date, 0, wx.EXPAND|wx.ALL)
234
235    #Location
236    label = wx.StaticText(self, -1, "Location")
237    labels.Add(label, 0, wx.EXPAND|wx.ALL, padding)
238    self.location = wx.TextCtrl(self, -1, '', size=(mbox,-1))
239    inputs.Add(self.location, 0, wx.EXPAND|wx.ALL)
240
241    #Organization
242    label = wx.StaticText(self, -1, "Organization")
243    labels.Add(label, 0, wx.EXPAND|wx.ALL, padding)
244    self.organization = wx.TextCtrl(self, -1, '', size=(mbox,-1))
245    inputs.Add(self.organization, 0, wx.EXPAND|wx.ALL)
246
247    #Copyright
248    label = wx.StaticText(self, -1, "Copyright")
249    labels.Add(label, 0, wx.EXPAND|wx.ALL, padding)
250    self.copyright = wx.TextCtrl(self, -1, '', size=(mbox,-1))
251    inputs.Add(self.copyright, 0, wx.EXPAND|wx.ALL)
252
253    #License
254    label = wx.StaticText(self, -1, "License")
255    labels.Add(label, 0, wx.EXPAND|wx.ALL, padding)
256    self.license = wx.TextCtrl(self, -1, '', size=(mbox,-1))
257    inputs.Add(self.license, 0, wx.EXPAND|wx.ALL)
258
259    #Contact
260    label = wx.StaticText(self, -1, "Contact")
261    labels.Add(label, 0, wx.EXPAND|wx.ALL, padding)
262    self.contact = wx.TextCtrl(self, -1, '', size=(mbox,-1))
263    inputs.Add(self.contact, 0, wx.EXPAND|wx.ALL)
264    '''
265
266    #Buttons
267    hbox = wx.BoxSizer(wx.HORIZONTAL)
268    mainBox.Add(hbox)
269    hbox.AddSpacer((8, 16))
270
271    hbox = wx.BoxSizer(wx.HORIZONTAL)
272    mainBox.Add(hbox)
273    hbox.AddSpacer((280, 10))
274    self.btnCancel = wx.Button(self, wx.ID_CANCEL)
275    self.btnCancel.SetLabel('Cancel')
276    hbox.Add(self.btnCancel, 0, wx.EXPAND|wx.ALL, padding)
277
278    self.btnOK = wx.Button(self, wx.ID_OK)
279    self.btnOK.SetDefault()
280    self.btnOK.Disable()
281    self.btnOK.SetLabel('Add to queue')
282    hbox.Add(self.btnOK, 0, wx.EXPAND|wx.ALL, padding)
283
284    hbox = wx.BoxSizer(wx.HORIZONTAL)
285    mainBox.Add(hbox)
286    hbox.AddSpacer((8, 8))
287
288
289    self.SetSizerAndFit(mainBox)
290
291    if parent.inputFile and os.path.exists(parent.inputFile):
292      self.selectVideoFile(parent.inputFile)
293    parent.inputFile = None
294
295  def OnClickVideoFile(self, event):
296    #transcoding later...
297    wildcard = "Video files|*.OGG;*.ogg;*.OGV;*.ogv;*.AVI;*.avi;*.mov;*.MOV;*.dv;*.DV;*.mp4;*.MP4;*.m4v;*.mpg;*.mpeg;*.wmv;*.MPG;*.flv;*.FLV|All Files (*.*)|*.*"
298    dialogOptions = dict()
299    dialogOptions['message'] = 'Add Video..'
300    dialogOptions['wildcard'] = wildcard
301    dialog = wx.FileDialog(self, **dialogOptions)
302    if dialog.ShowModal() == wx.ID_OK:
303      filename = dialog.GetFilename()
304      dirname = dialog.GetDirectory()
305      self.selectVideoFile(os.path.join(dirname, filename))
306    else:
307      filename=None
308    dialog.Destroy()
309    return filename
310
311  def selectVideoFile(self, videoFile):
312        self.info = theoraenc.fileInfo(videoFile)
313        if self.info:
314          #FIXME: enable/disable options based on input
315          """
316          if "video" in self.info: #source has video
317            #enable video options
318          if "audio" in self.info: #source has audio
319            #enable audio options
320          if "audio" in self.info: #source has audio
321
322          """
323          self.videoFile = videoFile
324          lValue = videoFile
325          lLength = 45
326          if len(lValue) > lLength:
327            lValue = "..." + lValue[-lLength:]
328          self.btnVideoFile.SetLabel(lValue)
329          self.btnOK.Enable()
330
331  def CheckSubtitlesSelection(self, event):
332    idx=self.subtitles.GetFirstSelected()
333    if idx<0:
334      self.btnSubtitlesRemove.Disable()
335      self.btnSubtitlesProperties.Disable()
336    else:
337      self.btnSubtitlesRemove.Enable()
338      self.btnSubtitlesProperties.Enable()
339    self.subtitles.ResizeFilenameColumn()
340
341  def OnClickSubtitlesAdd(self, event):
342    self.subtitles.Append(['', '', '', ''])
343    if not self.ChangeSubtitlesProperties(self.subtitles.GetItemCount()-1):
344      self.subtitles.DeleteItem(self.subtitles.GetItemCount()-1)
345    self.subtitles.ResizeFilenameColumn()
346
347  def OnClickSubtitlesRemove(self, event):
348    while 1:
349      idx=self.subtitles.GetFirstSelected()
350      if idx<0:
351         break
352      self.subtitles.DeleteItem(idx)
353    self.CheckSubtitlesSelection(event)
354
355  def OnClickSubtitlesProperties(self, event):
356    idx=self.subtitles.GetFirstSelected()
357    if idx<0:
358       return
359    self.ChangeSubtitlesProperties(idx)
360
361  def ChangeSubtitlesProperties(self, idx):
362    language = self.subtitles.GetItem(idx, 0).GetText()
363    category = self.subtitles.GetItem(idx, 1).GetText()
364    encoding = self.subtitles.GetItem(idx, 2).GetText()
365    file = self.subtitles.GetItem(idx, 3).GetText()
366    result = addSubtitlesPropertiesDialog(self, language, category, encoding, file, self.hasIconv)
367    time.sleep(0.5) # why ? race condition ?
368    if result['ok']:
369      self.subtitles.SetStringItem(idx, 0, result['subtitlesLanguage'])
370      self.subtitles.SetStringItem(idx, 1, result['subtitlesCategory'])
371      self.subtitles.SetStringItem(idx, 2, result['subtitlesEncoding'])
372      self.subtitles.SetStringItem(idx, 3, result['subtitlesFile'])
373      return True
374    else:
375      return False
376
377
378def addVideoDialog(parent, hasKate, hasIconv):
379  dlg = AddVideoDialog(parent, -1, "Add Video", hasKate, hasIconv, size=(490, 560), style=wx.DEFAULT_DIALOG_STYLE)
380  dlg.CenterOnScreen()
381  val = dlg.ShowModal()
382  result = dict()
383  if val == wx.ID_OK:
384    result['ok'] = True
385    result['videoFile'] = dlg.videoFile
386    for key in ('width', 'height', 'videoquality', 'videobitrate', 'framerate',
387                'audioquality', 'audiobitrate', 'samplerate'):
388      result[key] = getattr(dlg, key).GetValue()
389    # subtitles
390    if dlg.subtitles:
391      for idx in range(dlg.subtitles.GetItemCount()):
392        if not 'subtitles' in result:
393          result['subtitles'] = []
394        language = dlg.subtitles.GetItem(idx, 0).GetText()
395        category = dlg.subtitles.GetItem(idx, 1).GetText()
396        encoding = dlg.subtitles.GetItem(idx, 2).GetText()
397        file = dlg.subtitles.GetItem(idx, 3).GetText()
398        result['subtitles'].append({'encoding':encoding, 'language':language, 'category':category, 'file':file})
399  else:
400    result['ok'] = False
401  dlg.Destroy()
402  return result
403if __name__ == "__main__":
404  import sys
405  class Frame(wx.Frame):
406    inputFile = None
407    def __init__(self):
408      wx.Frame.__init__(self, None, wx.ID_ANY, "add video test", size=(559,260))
409      self.Show(True)
410
411  app = wx.PySimpleApp()
412  frame=Frame()
413  if len(sys.argv) > 1:
414    frame.inputFile = sys.argv[1]
415  result = addVideoDialog(frame, True)
416  print result
417
418