Advertisement
yclee126

dnd universial converter

Nov 16th, 2021
190
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.79 KB | None | 0 0
  1. #!/usr/bin/env python3.9
  2. # Simple drag and drop converter app
  3.  
  4. import wx
  5. from wx.adv import AboutDialogInfo, GenericAboutBox
  6. from threading import Thread
  7. from pathlib import Path
  8. import os
  9. import sys
  10. import numpy as np
  11. import subprocess
  12.  
  13.  
  14. choices = ['.m4a', '.mp3', '.acc']
  15.  
  16. if os.name == 'nt':
  17. import ctypes
  18. ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID('UniConv_v0.0.0')
  19.  
  20. class RedirectStdoutToTextCtrl():
  21. def __init__(self, widget):
  22. sys.stdout = self
  23. sys.stderr = self
  24. self.widget = widget
  25.  
  26. def write(self, message):
  27. self.widget.WriteText(message)
  28. return len(message)
  29.  
  30. def read(self):
  31. pass
  32.  
  33. def __del__(self):
  34. sys.stdout = sys.__stdout__
  35.  
  36.  
  37. class GUI(wx.Frame):
  38. def __init__(self, parent, id, title):
  39. wx.Frame.__init__(self, parent, id, title)
  40. self.SetSize((300, 200))
  41.  
  42. # pretty icon
  43. def getIcon():
  44. x, y = 256, 256
  45. img = np.zeros((x*y), dtype='uint8')
  46.  
  47. for i in range(y):
  48. for j in range(x):
  49. f = j/x
  50. img[i*y+j] = int((4*f**3 if f < 0.5 else 1-(-2*f+2)**3/2)*256) # cubic ease function
  51.  
  52. img = np.repeat(img, 3)
  53. icon = wx.Bitmap.FromBuffer(x, y, img)
  54. return icon
  55. self.SetIcon(wx.Icon(getIcon()))
  56.  
  57. # main panel
  58. self.panel = wx.Panel(self)
  59. self.panel.SetDropTarget(self.FileDrop(self)) # set DND
  60.  
  61. # main sizer
  62. vSizer = wx.BoxSizer(wx.VERTICAL)
  63. self.panel.SetSizer(vSizer)
  64.  
  65. # dropdown list
  66. self.comboBox = wx.ComboBox(self.panel, choices=choices)
  67. vSizer.Add(self.comboBox, flag=wx.EXPAND|wx.ALL, border=5)
  68. self.comboBox.SetSelection(0)
  69.  
  70. # logger panel
  71. self.loggerPanel = wx.Panel(self.panel)
  72. vSizer.Add(self.loggerPanel, flag=wx.EXPAND, proportion=1)
  73. self.logsUI(self.loggerPanel)
  74.  
  75. self.Centre()
  76. self.panel.Layout()
  77.  
  78. def logsUI(self, panel):
  79. sizer = wx.BoxSizer(wx.VERTICAL)
  80. panel.SetSizer(sizer)
  81.  
  82. self.logsTextCtrl = wx.TextCtrl(panel, style=wx.TE_MULTILINE, size=(222, 0))
  83. sizer.Add(self.logsTextCtrl, flag=wx.ALL|wx.EXPAND, border=5, proportion=1)
  84. self.logsTextCtrl.WriteText('Right click to clear the logs.\n\n')
  85. self.stdout = RedirectStdoutToTextCtrl(self.logsTextCtrl)
  86.  
  87. def onContextMenu(evt):
  88. menu = wx.Menu()
  89.  
  90. clearLog = menu.Append(wx.ID_ANY, "Clear log")
  91. menu.Bind(wx.EVT_MENU, lambda _: self.logsTextCtrl.Clear(), id=clearLog.GetId())
  92.  
  93. self.logsTextCtrl.PopupMenu(menu)
  94. self.logsTextCtrl.Bind(wx.EVT_CONTEXT_MENU, onContextMenu)
  95.  
  96. def workerThread(self, files, extension):
  97. failed_files = []
  98.  
  99. for i, file in enumerate(files):
  100. print(f'\nFile {i+1}/{len(files)}')
  101. file_path = Path(file).resolve()
  102. output_path = str(file_path.parent)
  103.  
  104. file_name = f'%s{extension}' % str(file_path.stem)
  105. output_file = os.path.join(output_path, file_name)
  106.  
  107. # process file
  108. result = False
  109. try:
  110. result = subprocess.run(['ffmpeg', '-i', file, '-vn', '-acodec', 'copy', output_file]) # redirecting is a bit harder. https://docs.python.org/3/library/subprocess.html#subprocess.Popen.communicate
  111. result = result.returncode == 0
  112. except:
  113. print('An error has occured!')
  114.  
  115. if not result:
  116. failed_files.append(file)
  117.  
  118. if failed_files:
  119. failMsg = f'\n{len(failed_files)} file(s) failed to process:'
  120. print(failMsg)
  121. for failed_file in failed_files:
  122. print(failed_file)
  123. wx.MessageDialog(self, 'An error has occurred. Please check the log.', 'Error', wx.OK|wx.ICON_ERROR).ShowModal()
  124. else:
  125. print('\nAll files converted.')
  126.  
  127. class FileDrop(wx.FileDropTarget):
  128. def __init__(self, parent):
  129. wx.FileDropTarget.__init__(self)
  130. self.parent = parent
  131.  
  132. def OnDropFiles(self, x, y, filenames):
  133. extension = self.parent.comboBox.GetString(self.parent.comboBox.GetSelection())
  134. Thread(target=self.parent.workerThread, daemon=True, args=(filenames, extension)).start()
  135. return True
  136.  
  137. def main():
  138. app = wx.App()
  139. gui = GUI(None, wx.ID_ANY, 'UniConv')
  140. gui.Show(True)
  141. app.MainLoop()
  142.  
  143. if __name__ == '__main__':
  144. main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement