You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1332 lines
51 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. #! /usr/bin/env python
  2. from time import time
  3. import wx
  4. from wx.lib.pubsub import setuparg1
  5. from wx.lib.pubsub import pub as Publisher
  6. from wx.lib.mixins.listctrl import ListCtrlAutoWidthMixin
  7. from .version import __version__
  8. from .UpdateThread import UpdateThread
  9. from .LogManager import LogManager, LogGUI
  10. from .OptionsHandler import OptionsHandler
  11. from .DownloadThread import DownloadManager
  12. from .Utils import (
  13. get_youtubedl_filename,
  14. get_user_config_path,
  15. video_is_dash,
  16. audio_is_dash,
  17. get_icon_path,
  18. shutdown_sys,
  19. file_exist,
  20. get_time,
  21. fix_path,
  22. open_dir,
  23. os_type
  24. )
  25. from .data import (
  26. __author__,
  27. __appname__,
  28. __projecturl__,
  29. __licensefull__,
  30. __descriptionfull__
  31. )
  32. AUDIO_FORMATS = ["mp3", "wav", "aac", "m4a"]
  33. VIDEO_FORMATS = [
  34. "default",
  35. "mp4 [1280x720]",
  36. "mp4 [640x360]",
  37. "webm [640x360]",
  38. "flv [400x240]",
  39. "3gp [320x240]",
  40. "mp4 1080p(DASH)",
  41. "mp4 720p(DASH)",
  42. "mp4 480p(DASH)",
  43. "mp4 360p(DASH)"
  44. ]
  45. DASH_AUDIO_FORMATS = [
  46. "none",
  47. "DASH m4a audio 128k",
  48. "DASH webm audio 48k"
  49. ]
  50. SUBS_LANG = [
  51. "English",
  52. "Greek",
  53. "Portuguese",
  54. "French",
  55. "Italian",
  56. "Russian",
  57. "Spanish",
  58. "German"
  59. ]
  60. ICON = get_icon_path()
  61. CONFIG_PATH = fix_path(get_user_config_path()) + __appname__.lower()
  62. class MainFrame(wx.Frame):
  63. def __init__(self, parent=None, id=-1):
  64. wx.Frame.__init__(self, parent, id, __appname__, size=(650, 440))
  65. # init gui
  66. self.init_gui()
  67. # set app icon
  68. if ICON is not None:
  69. self.SetIcon(wx.Icon(ICON, wx.BITMAP_TYPE_PNG))
  70. # set publisher for update thread
  71. Publisher.subscribe(self.update_handler, "update")
  72. # set publisher for download thread
  73. Publisher.subscribe(self.download_handler, "download_manager")
  74. Publisher.subscribe(self.download_handler, "download_thread")
  75. # init variables
  76. self.successful_downloads = 0
  77. self.timer = 0
  78. self.ori_url_list = []
  79. self.opt_manager = None
  80. self.log_manager = None
  81. self.update_thread = None
  82. self.download_thread = None
  83. # init Options
  84. self.opt_manager = OptionsHandler(CONFIG_PATH)
  85. # init log manager
  86. if self.opt_manager.options['enable_log']:
  87. self.log_manager = LogManager(
  88. CONFIG_PATH,
  89. self.opt_manager.options['log_time']
  90. )
  91. def init_gui(self):
  92. self.panel = wx.Panel(self)
  93. MainBoxSizer = wx.BoxSizer(wx.VERTICAL)
  94. # Url label
  95. URLTextBox = wx.BoxSizer(wx.HORIZONTAL)
  96. URLTextBox.Add(wx.StaticText(self.panel, label='URLs'), flag=wx.TOP, border=10)
  97. MainBoxSizer.Add(URLTextBox, flag=wx.LEFT, border=20)
  98. # Urls list
  99. URLBox = wx.BoxSizer(wx.HORIZONTAL)
  100. self.url_list = wx.TextCtrl(self.panel, size=(-1, 120), style=wx.TE_MULTILINE | wx.TE_DONTWRAP)
  101. URLBox.Add(self.url_list, 1)
  102. MainBoxSizer.Add(URLBox, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=20)
  103. # Buttons
  104. ButtonsBox = wx.BoxSizer(wx.HORIZONTAL)
  105. self.download_button = wx.Button(self.panel, label='Download', size=(90, 30))
  106. ButtonsBox.Add(self.download_button)
  107. self.update_button = wx.Button(self.panel, label='Update', size=(90, 30))
  108. ButtonsBox.Add(self.update_button, flag=wx.LEFT | wx.RIGHT, border=80)
  109. self.options_button = wx.Button(self.panel, label='Options', size=(90, 30))
  110. ButtonsBox.Add(self.options_button)
  111. MainBoxSizer.Add(ButtonsBox, flag=wx.ALIGN_CENTER_HORIZONTAL | wx.BOTTOM | wx.TOP, border=10)
  112. # Status list
  113. StatusListBox = wx.BoxSizer(wx.HORIZONTAL)
  114. self.status_list = ListCtrl(self.panel, style=wx.LC_REPORT | wx.LC_HRULES | wx.LC_VRULES)
  115. StatusListBox.Add(self.status_list, 1, flag=wx.EXPAND)
  116. MainBoxSizer.Add(StatusListBox, 1, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=20)
  117. # Status bar
  118. StatusBarBox = wx.BoxSizer(wx.HORIZONTAL)
  119. self.status_bar = wx.StaticText(self.panel, label='Author: ' + __author__)
  120. StatusBarBox.Add(self.status_bar, flag=wx.TOP | wx.BOTTOM, border=5)
  121. MainBoxSizer.Add(StatusBarBox, flag=wx.LEFT, border=20)
  122. self.panel.SetSizer(MainBoxSizer)
  123. # bind events
  124. self.Bind(wx.EVT_BUTTON, self.OnDownload, self.download_button)
  125. self.Bind(wx.EVT_BUTTON, self.OnUpdate, self.update_button)
  126. self.Bind(wx.EVT_BUTTON, self.OnOptions, self.options_button)
  127. self.Bind(wx.EVT_TEXT, self.OnTrackListChange, self.url_list)
  128. self.Bind(wx.EVT_CLOSE, self.OnClose)
  129. def youtubedl_exist(self):
  130. path = fix_path(self.opt_manager.options['youtubedl_path'])
  131. path += get_youtubedl_filename()
  132. if file_exist(path):
  133. return True
  134. return False
  135. def update_youtubedl(self):
  136. self.update_button.Disable()
  137. self.download_button.Disable()
  138. self.update_thread = UpdateThread(self.opt_manager.options['youtubedl_path'])
  139. def status_bar_write(self, msg):
  140. self.status_bar.SetLabel(msg)
  141. def reset(self):
  142. ''' Reset GUI and variables '''
  143. self.download_button.SetLabel('Download')
  144. self.successful_downloads = 0
  145. self.update_button.Enable()
  146. self.download_thread.join()
  147. self.download_thread = None
  148. self.ori_url_list = []
  149. self.timer = 0
  150. def fin_tasks(self):
  151. if self.opt_manager.options['shutdown']:
  152. self.save_options()
  153. shutdown_sys(self.opt_manager.options['sudo_password'])
  154. else:
  155. self.finished_popup()
  156. self.open_destination_dir()
  157. def open_destination_dir(self):
  158. if self.opt_manager.options['open_dl_dir']:
  159. open_dir(self.opt_manager.options['save_path'])
  160. def fin_message(self):
  161. if self.successful_downloads == 0:
  162. self.status_bar_write('Done')
  163. return
  164. current_time = time()
  165. dtime = get_time(current_time - self.timer)
  166. msg = 'Downloaded %s url(s) in ' % self.successful_downloads
  167. days = int(dtime['days'])
  168. hours = int(dtime['hours'])
  169. minutes = int(dtime['minutes'])
  170. seconds = int(dtime['seconds'])
  171. if days != 0:
  172. msg += '%s days, ' % days
  173. if hours != 0:
  174. msg += '%s hours, ' % hours
  175. if minutes != 0:
  176. msg += '%s minutes, ' % minutes
  177. msg += '%s seconds ' % seconds
  178. self.status_bar_write(msg)
  179. def download_handler(self, msg):
  180. topic = msg.topic[0]
  181. data = msg.data
  182. # Report downloading videos number
  183. videos_no = self.download_thread.get_items_counter()
  184. self.status_bar_write('Downloading %s url(s)' % videos_no)
  185. if topic == 'download_thread':
  186. self.status_list.write(data)
  187. if data['status'] == 'Finished' or data['status'] == 'Already-Downloaded':
  188. self.successful_downloads += 1
  189. if topic == 'download_manager':
  190. if data == 'closing':
  191. self.status_bar_write('Stopping downloads')
  192. if data == 'closed':
  193. self.status_bar_write('Downloads stopped')
  194. self.reset()
  195. if data == 'finished':
  196. self.fin_message()
  197. self.reset()
  198. self.fin_tasks()
  199. def update_handler(self, msg):
  200. if msg.data == 'finish':
  201. self.update_thread.join()
  202. self.update_thread = None
  203. self.update_button.Enable()
  204. self.download_button.Enable()
  205. else:
  206. self.status_bar_write(msg.data)
  207. def stop_download(self):
  208. self.download_thread.close()
  209. def load_on_list(self, url):
  210. url = url.replace(' ', '')
  211. if url not in self.ori_url_list and url != '':
  212. self.ori_url_list.append(url)
  213. self.status_list.add_item(url)
  214. return True
  215. return False
  216. def start_download(self):
  217. self.status_list.clear_list()
  218. for url in self.url_list.GetValue().split('\n'):
  219. self.load_on_list(url)
  220. if not self.status_list.is_empty():
  221. self.download_thread = DownloadManager(
  222. self.status_list.get_items(),
  223. self.opt_manager,
  224. self.log_manager
  225. )
  226. self.timer = time()
  227. self.status_bar_write('Download started')
  228. self.download_button.SetLabel('Stop')
  229. self.update_button.Disable()
  230. else:
  231. self.no_url_popup()
  232. def save_options(self):
  233. self.opt_manager.save_to_file()
  234. def finished_popup(self):
  235. wx.MessageBox('Downloads completed.', 'Info', wx.OK | wx.ICON_INFORMATION)
  236. def no_url_popup(self):
  237. wx.MessageBox('You need to provide at least one url.', 'Error', wx.OK | wx.ICON_EXCLAMATION)
  238. def download_ydl_popup(self):
  239. dial = wx.MessageDialog(self,
  240. 'Youtube-dl is missing.\nWould you like to download it?',
  241. 'Error',
  242. wx.YES_NO | wx.ICON_ERROR)
  243. return (dial.ShowModal() == wx.ID_YES)
  244. def OnTrackListChange(self, event):
  245. ''' Dynamicaly add urls for download '''
  246. if self.download_thread is not None:
  247. for url in self.url_list.GetValue().split('\n'):
  248. if self.load_on_list(url):
  249. item = self.status_list.get_last_item()
  250. self.download_thread.add_download_item(item)
  251. def OnDownload(self, event):
  252. if self.download_thread is None:
  253. if self.youtubedl_exist():
  254. self.start_download()
  255. elif self.download_ydl_popup():
  256. self.update_youtubedl()
  257. else:
  258. self.stop_download()
  259. def OnUpdate(self, event):
  260. if self.download_thread is None and self.update_thread is None:
  261. self.update_youtubedl()
  262. def OnOptions(self, event):
  263. opts_frame = OptionsFrame(self.opt_manager, parent=self, logger=self.log_manager)
  264. opts_frame.Show()
  265. def OnClose(self, event):
  266. if self.download_thread is not None:
  267. self.download_thread.close(kill=True)
  268. self.download_thread.join()
  269. self.save_options()
  270. self.Destroy()
  271. class ListCtrl(wx.ListCtrl, ListCtrlAutoWidthMixin):
  272. ''' Custom ListCtrl class '''
  273. # Hold column for each data
  274. DATA_COLUMNS = {
  275. 'filename': 0,
  276. 'filesize': 1,
  277. 'percent': 2,
  278. 'status': 5,
  279. 'speed': 4,
  280. 'eta': 3
  281. }
  282. def __init__(self, parent=None, id=-1, pos=wx.DefaultPosition, size=wx.DefaultSize, style=0):
  283. wx.ListCtrl.__init__(self, parent, id, pos, size, style)
  284. ListCtrlAutoWidthMixin.__init__(self)
  285. self.InsertColumn(0, 'Video', width=150)
  286. self.InsertColumn(1, 'Size', width=80)
  287. self.InsertColumn(2, 'Percent', width=65)
  288. self.InsertColumn(3, 'ETA', width=45)
  289. self.InsertColumn(4, 'Speed', width=90)
  290. self.InsertColumn(5, 'Status', width=160)
  291. self.setResizeColumn(0)
  292. self.list_index = 0
  293. def write(self, data):
  294. ''' Write data on ListCtrl '''
  295. index = data['index']
  296. for key in data:
  297. if key in self.DATA_COLUMNS:
  298. self._write_data(data[key], index, self.DATA_COLUMNS[key])
  299. def add_item(self, item):
  300. ''' Add single item on ListCtrl '''
  301. self.InsertStringItem(self.list_index, item)
  302. self.list_index += 1
  303. def clear_list(self):
  304. self.DeleteAllItems()
  305. self.list_index = 0
  306. def is_empty(self):
  307. return (self.list_index == 0)
  308. def get_items(self, start_index=0):
  309. ''' Return list of items starting from start_index '''
  310. items = []
  311. for row in range(start_index, self.list_index):
  312. item = self._get_item(row)
  313. items.append(item)
  314. return items
  315. def get_last_item(self):
  316. ''' Return last item of ListCtrl '''
  317. return self._get_item(self.list_index - 1)
  318. def _write_data(self, data, row, column):
  319. ''' Write data on row, column '''
  320. if isinstance(data, basestring):
  321. self.SetStringItem(row, column, data)
  322. def _get_item(self, index):
  323. ''' Return single item from index '''
  324. data = {}
  325. item = self.GetItem(itemId=index, col=0)
  326. data['url'] = item.GetText()
  327. data['index'] = index
  328. return data
  329. class LogPanel(wx.Panel):
  330. win_border = 0
  331. def __init__(self, parent, opt_manager, logger):
  332. wx.Panel.__init__(self, parent)
  333. self.set_win_border()
  334. self.opt_manager = opt_manager
  335. self.logger = logger
  336. MainBoxSizer = wx.BoxSizer(wx.VERTICAL)
  337. EnableLogBox = wx.BoxSizer(wx.HORIZONTAL)
  338. self.enable_log_checkbox = wx.CheckBox(self, label='Enable Log')
  339. EnableLogBox.Add(self.enable_log_checkbox)
  340. MainBoxSizer.Add(EnableLogBox, flag=wx.ALIGN_CENTER_HORIZONTAL | wx.TOP, border=20 + self.win_border)
  341. LogTimeBox = wx.BoxSizer(wx.HORIZONTAL)
  342. self.log_time_checkbox = wx.CheckBox(self, label='Write Time')
  343. LogTimeBox.Add(self.log_time_checkbox)
  344. MainBoxSizer.Add(LogTimeBox, flag=wx.ALIGN_CENTER_HORIZONTAL | wx.TOP, border=5 + self.win_border)
  345. ButtonsBox = wx.BoxSizer(wx.HORIZONTAL)
  346. self.clear_log_button = wx.Button(self, label='Clear Log')
  347. ButtonsBox.Add(self.clear_log_button)
  348. self.view_log_button = wx.Button(self, label='View Log')
  349. ButtonsBox.Add(self.view_log_button, flag=wx.LEFT, border=20)
  350. MainBoxSizer.Add(ButtonsBox, flag=wx.ALIGN_CENTER_HORIZONTAL | wx.TOP, border=15)
  351. if self.opt_manager.options['enable_log']:
  352. LogPathBox = wx.BoxSizer(wx.HORIZONTAL)
  353. LogPathBox.Add(wx.StaticText(self, label='Path: ' + self.get_path()))
  354. MainBoxSizer.Add(LogPathBox, flag=wx.ALIGN_CENTER_HORIZONTAL | wx.TOP, border=20)
  355. LogSizeBox = wx.BoxSizer(wx.HORIZONTAL)
  356. self.size_text = wx.StaticText(self, label='Log Size: ' + self.get_size())
  357. LogSizeBox.Add(self.size_text)
  358. MainBoxSizer.Add(LogSizeBox, flag=wx.ALIGN_CENTER_HORIZONTAL | wx.TOP, border=10)
  359. self.SetSizer(MainBoxSizer)
  360. self.Bind(wx.EVT_CHECKBOX, self.OnEnable, self.enable_log_checkbox)
  361. self.Bind(wx.EVT_CHECKBOX, self.OnTime, self.log_time_checkbox)
  362. self.Bind(wx.EVT_BUTTON, self.OnClear, self.clear_log_button)
  363. self.Bind(wx.EVT_BUTTON, self.OnView, self.view_log_button)
  364. def set_win_border(self):
  365. if os_type == 'nt':
  366. self.win_border = 10
  367. def get_path(self):
  368. ''' Return log file abs path '''
  369. return self.logger.log_file
  370. def get_size(self):
  371. ''' Return log file size in Bytes '''
  372. return str(self.logger.size()) + ' Byte(s)'
  373. def restart_popup(self):
  374. wx.MessageBox('Please restart ' + __appname__, 'Restart', wx.OK | wx.ICON_INFORMATION)
  375. def OnTime(self, event):
  376. if self.logger is not None:
  377. self.logger.add_time = self.log_time_checkbox.GetValue()
  378. def OnEnable(self, event):
  379. self.restart_popup()
  380. def OnClear(self, event):
  381. if self.logger is not None:
  382. self.logger.clear()
  383. self.size_text.SetLabel('Log Size: ' + self.get_size())
  384. def OnView(self, event):
  385. if self.logger is not None:
  386. logger_gui = LogGUI(self.get_path(), parent=self)
  387. logger_gui.Show()
  388. def load_options(self):
  389. self.enable_log_checkbox.SetValue(self.opt_manager.options['enable_log'])
  390. self.log_time_checkbox.SetValue(self.opt_manager.options['log_time'])
  391. if self.logger is None:
  392. self.log_time_checkbox.Disable()
  393. self.clear_log_button.Disable()
  394. self.view_log_button.Disable()
  395. def save_options(self):
  396. self.opt_manager.options['enable_log'] = self.enable_log_checkbox.GetValue()
  397. self.opt_manager.options['log_time'] = self.log_time_checkbox.GetValue()
  398. class ShutdownPanel(wx.Panel):
  399. def __init__(self, parent, opt_manager):
  400. wx.Panel.__init__(self, parent)
  401. self.opt_manager = opt_manager
  402. MainBoxSizer = wx.BoxSizer(wx.VERTICAL)
  403. ShutdownBox = wx.BoxSizer(wx.HORIZONTAL)
  404. self.shutdown_checkbox = wx.CheckBox(self, label='Shutdown when finished')
  405. ShutdownBox.Add(self.shutdown_checkbox)
  406. MainBoxSizer.Add(ShutdownBox, flag=wx.ALIGN_CENTER_HORIZONTAL | wx.TOP, border=30)
  407. SUDOTextBox = wx.BoxSizer(wx.HORIZONTAL)
  408. SUDOTextBox.Add(wx.StaticText(self, label='SUDO password'))
  409. MainBoxSizer.Add(SUDOTextBox, flag=wx.ALIGN_CENTER_HORIZONTAL | wx.TOP, border=20)
  410. SUDOBox = wx.BoxSizer(wx.HORIZONTAL)
  411. self.sudo_pass_box = wx.TextCtrl(self, size=(-1, 25), style=wx.TE_PASSWORD)
  412. SUDOBox.Add(self.sudo_pass_box, 1, flag=wx.TOP, border=5)
  413. MainBoxSizer.Add(SUDOBox, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=160)
  414. self.SetSizer(MainBoxSizer)
  415. self.Bind(wx.EVT_CHECKBOX, self.OnShutdownCheck, self.shutdown_checkbox)
  416. def OnShutdownCheck(self, event):
  417. if os_type != 'nt':
  418. if self.shutdown_checkbox.GetValue():
  419. self.sudo_pass_box.Enable()
  420. else:
  421. self.sudo_pass_box.Disable()
  422. def load_options(self):
  423. self.shutdown_checkbox.SetValue(self.opt_manager.options['shutdown'])
  424. self.sudo_pass_box.SetValue(self.opt_manager.options['sudo_password'])
  425. if os_type == 'nt' or not self.opt_manager.options['shutdown']:
  426. self.sudo_pass_box.Disable()
  427. def save_options(self):
  428. self.opt_manager.options['shutdown'] = self.shutdown_checkbox.GetValue()
  429. self.opt_manager.options['sudo_password'] = self.sudo_pass_box.GetValue()
  430. class PlaylistPanel(wx.Panel):
  431. def __init__(self, parent, opt_manager):
  432. wx.Panel.__init__(self, parent)
  433. self.opt_manager = opt_manager
  434. MainBoxSizer = wx.StaticBoxSizer(wx.StaticBox(self, label='Playlist Options'), wx.VERTICAL)
  435. MainBoxSizer.Add((-1, 5))
  436. StartTextBox = wx.BoxSizer(wx.HORIZONTAL)
  437. StartTextBox.Add(wx.StaticText(self, label='Playlist Start'))
  438. MainBoxSizer.Add(StartTextBox, flag=wx.ALIGN_CENTER_HORIZONTAL | wx.TOP, border=5)
  439. StartBox = wx.BoxSizer(wx.HORIZONTAL)
  440. self.start_spinner = wx.SpinCtrl(self, size=(70, 20))
  441. self.start_spinner.SetRange(1, 999)
  442. StartBox.Add(self.start_spinner)
  443. MainBoxSizer.Add(StartBox, flag=wx.ALIGN_CENTER_HORIZONTAL | wx.TOP, border=5)
  444. StopTextBox = wx.BoxSizer(wx.HORIZONTAL)
  445. StopTextBox.Add(wx.StaticText(self, label='Playlist Stop'))
  446. MainBoxSizer.Add(StopTextBox, flag=wx.ALIGN_CENTER_HORIZONTAL | wx.TOP, border=15)
  447. StopBox = wx.BoxSizer(wx.HORIZONTAL)
  448. self.stop_spinner = wx.SpinCtrl(self, size=(70, 20))
  449. self.stop_spinner.SetRange(0, 999)
  450. StopBox.Add(self.stop_spinner)
  451. MainBoxSizer.Add(StopBox, flag=wx.ALIGN_CENTER_HORIZONTAL | wx.TOP, border=5)
  452. MaxTextBox = wx.BoxSizer(wx.HORIZONTAL)
  453. MaxTextBox.Add(wx.StaticText(self, label='Max Downloads'))
  454. MainBoxSizer.Add(MaxTextBox, flag=wx.ALIGN_CENTER_HORIZONTAL | wx.TOP, border=15)
  455. MaxBox = wx.BoxSizer(wx.HORIZONTAL)
  456. self.max_spinner = wx.SpinCtrl(self, size=(70, 20))
  457. self.max_spinner.SetRange(0, 999)
  458. MaxBox.Add(self.max_spinner)
  459. MainBoxSizer.Add(MaxBox, flag=wx.ALIGN_CENTER_HORIZONTAL | wx.TOP, border=5)
  460. self.SetSizer(MainBoxSizer)
  461. def load_options(self):
  462. self.start_spinner.SetValue(self.opt_manager.options['playlist_start'])
  463. self.stop_spinner.SetValue(self.opt_manager.options['playlist_end'])
  464. self.max_spinner.SetValue(self.opt_manager.options['max_downloads'])
  465. def save_options(self):
  466. self.opt_manager.options['playlist_start'] = self.start_spinner.GetValue()
  467. self.opt_manager.options['playlist_end'] = self.stop_spinner.GetValue()
  468. self.opt_manager.options['max_downloads'] = self.max_spinner.GetValue()
  469. class ConnectionPanel(wx.Panel):
  470. def __init__(self, parent, opt_manager):
  471. wx.Panel.__init__(self, parent)
  472. self.opt_manager = opt_manager
  473. MainBoxSizer = wx.BoxSizer(wx.VERTICAL)
  474. RetriesBox = wx.BoxSizer(wx.HORIZONTAL)
  475. RetriesBox.Add(wx.StaticText(self, label='Retries'), flag=wx.RIGHT, border=8)
  476. self.retries_spinner = wx.SpinCtrl(self, size=(50, -1))
  477. self.retries_spinner.SetRange(1, 99)
  478. RetriesBox.Add(self.retries_spinner)
  479. MainBoxSizer.Add(RetriesBox, flag=wx.LEFT | wx.TOP, border=10)
  480. UserAgentTextBox = wx.BoxSizer(wx.HORIZONTAL)
  481. UserAgentTextBox.Add(wx.StaticText(self, label='User Agent'), flag=wx.LEFT, border=15)
  482. MainBoxSizer.Add(UserAgentTextBox, flag=wx.TOP, border=10)
  483. MainBoxSizer.Add((-1, 5))
  484. UserAgentBox = wx.BoxSizer(wx.HORIZONTAL)
  485. self.user_agent_box = wx.TextCtrl(self)
  486. UserAgentBox.Add(self.user_agent_box, 1, flag=wx.LEFT, border=10)
  487. MainBoxSizer.Add(UserAgentBox, flag=wx.EXPAND | wx.RIGHT, border=200)
  488. RefererTextBox = wx.BoxSizer(wx.HORIZONTAL)
  489. RefererTextBox.Add(wx.StaticText(self, label='Referer'), flag=wx.LEFT, border=15)
  490. MainBoxSizer.Add(RefererTextBox, flag=wx.TOP, border=10)
  491. MainBoxSizer.Add((-1, 5))
  492. RefererBox = wx.BoxSizer(wx.HORIZONTAL)
  493. self.referer_box = wx.TextCtrl(self)
  494. RefererBox.Add(self.referer_box, 1, flag=wx.LEFT, border=10)
  495. MainBoxSizer.Add(RefererBox, flag=wx.EXPAND | wx.RIGHT, border=200)
  496. ProxyTextBox = wx.BoxSizer(wx.HORIZONTAL)
  497. ProxyTextBox.Add(wx.StaticText(self, label='Proxy'), flag=wx.LEFT, border=15)
  498. MainBoxSizer.Add(ProxyTextBox, flag=wx.TOP, border=10)
  499. MainBoxSizer.Add((-1, 5))
  500. ProxyBox = wx.BoxSizer(wx.HORIZONTAL)
  501. self.proxy_box = wx.TextCtrl(self)
  502. ProxyBox.Add(self.proxy_box, 1, flag=wx.LEFT, border=10)
  503. MainBoxSizer.Add(ProxyBox, flag=wx.EXPAND | wx.RIGHT, border=100)
  504. self.SetSizer(MainBoxSizer)
  505. def load_options(self):
  506. self.proxy_box.SetValue(self.opt_manager.options['proxy'])
  507. self.referer_box.SetValue(self.opt_manager.options['referer'])
  508. self.retries_spinner.SetValue(self.opt_manager.options['retries'])
  509. self.user_agent_box.SetValue(self.opt_manager.options['user_agent'])
  510. def save_options(self):
  511. self.opt_manager.options['proxy'] = self.proxy_box.GetValue()
  512. self.opt_manager.options['referer'] = self.referer_box.GetValue()
  513. self.opt_manager.options['retries'] = self.retries_spinner.GetValue()
  514. self.opt_manager.options['user_agent'] = self.user_agent_box.GetValue()
  515. class AuthenticationPanel(wx.Panel):
  516. def __init__(self, parent, opt_manager):
  517. wx.Panel.__init__(self, parent)
  518. self.opt_manager = opt_manager
  519. MainBoxSizer = wx.BoxSizer(wx.VERTICAL)
  520. UsernameTextBox = wx.BoxSizer(wx.HORIZONTAL)
  521. UsernameTextBox.Add(wx.StaticText(self, label='Username'))
  522. MainBoxSizer.Add(UsernameTextBox, flag=wx.ALIGN_CENTER_HORIZONTAL | wx.TOP, border=15)
  523. UsernameBox = wx.BoxSizer(wx.HORIZONTAL)
  524. self.username_box = wx.TextCtrl(self, size=(-1, 25))
  525. UsernameBox.Add(self.username_box, 1, flag=wx.TOP, border=5)
  526. MainBoxSizer.Add(UsernameBox, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=160)
  527. PassTextBox = wx.BoxSizer(wx.HORIZONTAL)
  528. PassTextBox.Add(wx.StaticText(self, label='Password'))
  529. MainBoxSizer.Add(PassTextBox, flag=wx.ALIGN_CENTER_HORIZONTAL | wx.TOP, border=15)
  530. PassBox = wx.BoxSizer(wx.HORIZONTAL)
  531. self.password_box = wx.TextCtrl(self, size=(-1, 25), style=wx.TE_PASSWORD)
  532. PassBox.Add(self.password_box, 1, flag=wx.TOP, border=5)
  533. MainBoxSizer.Add(PassBox, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=160)
  534. VideoPassTextBox = wx.BoxSizer(wx.HORIZONTAL)
  535. VideoPassTextBox.Add(wx.StaticText(self, label='Video Password (vimeo, smotri)'))
  536. MainBoxSizer.Add(VideoPassTextBox, flag=wx.ALIGN_CENTER_HORIZONTAL | wx.TOP, border=15)
  537. VideoPassBox = wx.BoxSizer(wx.HORIZONTAL)
  538. self.video_pass_box = wx.TextCtrl(self, size=(-1, 25), style=wx.TE_PASSWORD)
  539. VideoPassBox.Add(self.video_pass_box, 1, flag=wx.TOP, border=5)
  540. MainBoxSizer.Add(VideoPassBox, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=160)
  541. self.SetSizer(MainBoxSizer)
  542. def load_options(self):
  543. self.username_box.SetValue(self.opt_manager.options['username'])
  544. self.password_box.SetValue(self.opt_manager.options['password'])
  545. self.video_pass_box.SetValue(self.opt_manager.options['video_password'])
  546. def save_options(self):
  547. self.opt_manager.options['username'] = self.username_box.GetValue()
  548. self.opt_manager.options['password'] = self.password_box.GetValue()
  549. self.opt_manager.options['video_password'] = self.video_pass_box.GetValue()
  550. class AudioPanel(wx.Panel):
  551. win_border = 0
  552. AUDIO_QUALITY = ['high', 'mid', 'low']
  553. def __init__(self, parent, opt_manager):
  554. wx.Panel.__init__(self, parent)
  555. self.set_win_border()
  556. self.opt_manager = opt_manager
  557. MainBoxSizer = wx.BoxSizer(wx.VERTICAL)
  558. ToAudioBox = wx.BoxSizer(wx.HORIZONTAL)
  559. self.to_audio_checkbox = wx.CheckBox(self, label='Convert to Audio')
  560. ToAudioBox.Add(self.to_audio_checkbox)
  561. MainBoxSizer.Add(ToAudioBox, flag=wx.ALIGN_CENTER_HORIZONTAL | wx.TOP, border=15 + self.win_border)
  562. KeepVideoBox = wx.BoxSizer(wx.HORIZONTAL)
  563. self.keep_video_checkbox = wx.CheckBox(self, label='Keep Video')
  564. KeepVideoBox.Add(self.keep_video_checkbox)
  565. MainBoxSizer.Add(KeepVideoBox, flag=wx.ALIGN_CENTER_HORIZONTAL | wx.TOP, border=5 + self.win_border)
  566. AudioFormatTextBox = wx.BoxSizer(wx.HORIZONTAL)
  567. AudioFormatTextBox.Add(wx.StaticText(self, label='Audio Format'))
  568. MainBoxSizer.Add(AudioFormatTextBox, flag=wx.ALIGN_CENTER_HORIZONTAL | wx.TOP, border=10)
  569. AudioFormatBox = wx.BoxSizer(wx.HORIZONTAL)
  570. self.audio_format_combo = wx.ComboBox(self, choices=AUDIO_FORMATS, size=(160, 30))
  571. AudioFormatBox.Add(self.audio_format_combo)
  572. MainBoxSizer.Add(AudioFormatBox, flag=wx.ALIGN_CENTER_HORIZONTAL | wx.TOP, border=5)
  573. AudioQualityTextBox = wx.BoxSizer(wx.HORIZONTAL)
  574. AudioQualityTextBox.Add(wx.StaticText(self, label='Audio Quality'))
  575. MainBoxSizer.Add(AudioQualityTextBox, flag=wx.ALIGN_CENTER_HORIZONTAL | wx.TOP, border=10)
  576. AudioQualityBox = wx.BoxSizer(wx.HORIZONTAL)
  577. self.audio_quality_combo = wx.ComboBox(self, choices=self.AUDIO_QUALITY, size=(80, 25))
  578. AudioQualityBox.Add(self.audio_quality_combo)
  579. MainBoxSizer.Add(AudioQualityBox, flag=wx.ALIGN_CENTER_HORIZONTAL | wx.TOP, border=5)
  580. self.SetSizer(MainBoxSizer)
  581. self.Bind(wx.EVT_CHECKBOX, self.OnAudioCheck, self.to_audio_checkbox)
  582. def set_win_border(self):
  583. if os_type == 'nt':
  584. self.win_border = 5
  585. def OnAudioCheck(self, event):
  586. if self.to_audio_checkbox.GetValue():
  587. self.keep_video_checkbox.Enable()
  588. self.audio_format_combo.Enable()
  589. self.audio_quality_combo.Enable()
  590. else:
  591. self.keep_video_checkbox.Disable()
  592. self.audio_format_combo.Disable()
  593. self.audio_quality_combo.Disable()
  594. def load_options(self):
  595. self.to_audio_checkbox.SetValue(self.opt_manager.options['to_audio'])
  596. self.keep_video_checkbox.SetValue(self.opt_manager.options['keep_video'])
  597. self.audio_format_combo.SetValue(self.opt_manager.options['audio_format'])
  598. self.audio_quality_combo.SetValue(self.opt_manager.options['audio_quality'])
  599. self.OnAudioCheck(None)
  600. def save_options(self):
  601. self.opt_manager.options['to_audio'] = self.to_audio_checkbox.GetValue()
  602. self.opt_manager.options['keep_video'] = self.keep_video_checkbox.GetValue()
  603. self.opt_manager.options['audio_format'] = self.audio_format_combo.GetValue()
  604. self.opt_manager.options['audio_quality'] = self.audio_quality_combo.GetValue()
  605. class VideoPanel(wx.Panel):
  606. def __init__(self, parent, opt_manager):
  607. wx.Panel.__init__(self, parent)
  608. self.opt_manager = opt_manager
  609. MainBoxSizer = wx.BoxSizer(wx.VERTICAL)
  610. VideoFormatTextBox = wx.BoxSizer(wx.HORIZONTAL)
  611. VideoFormatTextBox.Add(wx.StaticText(self, label='Video Format'))
  612. MainBoxSizer.Add(VideoFormatTextBox, flag=wx.ALIGN_CENTER_HORIZONTAL | wx.TOP, border=20)
  613. VideoFormatBox = wx.BoxSizer(wx.HORIZONTAL)
  614. self.video_format_combo = wx.ComboBox(self, choices=VIDEO_FORMATS, size=(160, 30))
  615. VideoFormatBox.Add(self.video_format_combo)
  616. MainBoxSizer.Add(VideoFormatBox, flag=wx.ALIGN_CENTER_HORIZONTAL | wx.TOP, border=5)
  617. DASHAudioTextBox = wx.BoxSizer(wx.HORIZONTAL)
  618. DASHAudioTextBox.Add(wx.StaticText(self, label='DASH Audio'))
  619. MainBoxSizer.Add(DASHAudioTextBox, flag=wx.ALIGN_CENTER_HORIZONTAL | wx.TOP, border=10)
  620. DASHAudioBox = wx.BoxSizer(wx.HORIZONTAL)
  621. self.dash_audio_combo = wx.ComboBox(self, choices=DASH_AUDIO_FORMATS, size=(160, 30))
  622. DASHAudioBox.Add(self.dash_audio_combo)
  623. MainBoxSizer.Add(DASHAudioBox, flag=wx.ALIGN_CENTER_HORIZONTAL | wx.TOP, border=5)
  624. ClearDASHBox = wx.BoxSizer(wx.HORIZONTAL)
  625. self.clear_dash_checkbox = wx.CheckBox(self, label='Clear DASH audio/video files')
  626. ClearDASHBox.Add(self.clear_dash_checkbox)
  627. MainBoxSizer.Add(ClearDASHBox, flag=wx.ALIGN_CENTER_HORIZONTAL | wx.TOP, border=20)
  628. self.SetSizer(MainBoxSizer)
  629. self.Bind(wx.EVT_COMBOBOX, self.OnVideoFormatPick, self.video_format_combo)
  630. self.Bind(wx.EVT_COMBOBOX, self.OnAudioFormatPick, self.dash_audio_combo)
  631. def OnAudioFormatPick(self, event):
  632. if audio_is_dash(self.dash_audio_combo.GetValue()):
  633. self.clear_dash_checkbox.Enable()
  634. else:
  635. self.clear_dash_checkbox.SetValue(False)
  636. self.clear_dash_checkbox.Disable()
  637. def OnVideoFormatPick(self, event):
  638. if video_is_dash(self.video_format_combo.GetValue()):
  639. self.dash_audio_combo.Enable()
  640. if audio_is_dash(self.dash_audio_combo.GetValue()):
  641. self.clear_dash_checkbox.Enable()
  642. else:
  643. self.clear_dash_checkbox.SetValue(False)
  644. self.clear_dash_checkbox.Disable()
  645. self.dash_audio_combo.Disable()
  646. def load_options(self):
  647. self.video_format_combo.SetValue(self.opt_manager.options['video_format'])
  648. self.dash_audio_combo.SetValue(self.opt_manager.options['dash_audio_format'])
  649. self.clear_dash_checkbox.SetValue(self.opt_manager.options['clear_dash_files'])
  650. self.OnVideoFormatPick(None)
  651. self.OnAudioFormatPick(None)
  652. def save_options(self):
  653. self.opt_manager.options['video_format'] = self.video_format_combo.GetValue()
  654. self.opt_manager.options['dash_audio_format'] = self.dash_audio_combo.GetValue()
  655. self.opt_manager.options['clear_dash_files'] = self.clear_dash_checkbox.GetValue()
  656. class OutputPanel(wx.Panel):
  657. win_border = 0
  658. def __init__(self, parent, opt_manager):
  659. wx.Panel.__init__(self, parent)
  660. self.set_win_border()
  661. self.opt_manager = opt_manager
  662. MainBoxSizer = wx.BoxSizer(wx.VERTICAL)
  663. RestrictFilenameBox = wx.BoxSizer(wx.HORIZONTAL)
  664. self.restrict_filenames_checkbox = wx.CheckBox(self, label='Restrict filenames (ASCII)')
  665. RestrictFilenameBox.Add(self.restrict_filenames_checkbox, flag=wx.LEFT, border=5)
  666. MainBoxSizer.Add(RestrictFilenameBox, flag=wx.TOP, border=15)
  667. IDAsNameBox = wx.BoxSizer(wx.HORIZONTAL)
  668. self.id_as_name_checkbox = wx.CheckBox(self, label='ID as Name')
  669. IDAsNameBox.Add(self.id_as_name_checkbox, flag=wx.LEFT, border=5)
  670. MainBoxSizer.Add(IDAsNameBox, flag=wx.TOP, border=5 + self.win_border)
  671. TitleBox = wx.BoxSizer(wx.HORIZONTAL)
  672. self.title_checkbox = wx.CheckBox(self, label='Title as Name')
  673. TitleBox.Add(self.title_checkbox, flag=wx.LEFT, border=5)
  674. MainBoxSizer.Add(TitleBox, flag=wx.TOP, border=5 + self.win_border)
  675. CustomTitleBox = wx.BoxSizer(wx.HORIZONTAL)
  676. self.custom_title_checkbox = wx.CheckBox(self, label='Custom Template (youtube-dl)')
  677. CustomTitleBox.Add(self.custom_title_checkbox, flag=wx.LEFT, border=5)
  678. MainBoxSizer.Add(CustomTitleBox, flag=wx.TOP, border=5 + self.win_border)
  679. MainBoxSizer.Add((-1, 10))
  680. CustomTemplateBox = wx.BoxSizer(wx.HORIZONTAL)
  681. self.title_template_box = wx.TextCtrl(self)
  682. CustomTemplateBox.Add(self.title_template_box, 1, flag=wx.RIGHT, border=300)
  683. MainBoxSizer.Add(CustomTemplateBox, flag=wx.EXPAND | wx.LEFT, border=5)
  684. self.SetSizer(MainBoxSizer)
  685. self.Bind(wx.EVT_CHECKBOX, self.OnId, self.id_as_name_checkbox)
  686. self.Bind(wx.EVT_CHECKBOX, self.OnTitle, self.title_checkbox)
  687. self.Bind(wx.EVT_CHECKBOX, self.OnCustom, self.custom_title_checkbox)
  688. def set_win_border(self):
  689. if os_type == 'nt':
  690. self.win_border = 10
  691. def group_load(self, output_format):
  692. if output_format == 'id':
  693. self.id_as_name_checkbox.SetValue(True)
  694. self.title_checkbox.SetValue(False)
  695. self.custom_title_checkbox.SetValue(False)
  696. self.title_template_box.Disable()
  697. elif output_format == 'title':
  698. self.id_as_name_checkbox.SetValue(False)
  699. self.title_checkbox.SetValue(True)
  700. self.custom_title_checkbox.SetValue(False)
  701. self.title_template_box.Disable()
  702. elif output_format == 'custom':
  703. self.id_as_name_checkbox.SetValue(False)
  704. self.title_checkbox.SetValue(False)
  705. self.custom_title_checkbox.SetValue(True)
  706. self.title_template_box.Enable()
  707. def get_output_format(self):
  708. if self.id_as_name_checkbox.GetValue():
  709. return 'id'
  710. elif self.title_checkbox.GetValue():
  711. return 'title'
  712. elif self.custom_title_checkbox.GetValue():
  713. return 'custom'
  714. def OnId(self, event):
  715. self.group_load('id')
  716. def OnTitle(self, event):
  717. self.group_load('title')
  718. def OnCustom(self, event):
  719. self.group_load('custom')
  720. def load_options(self):
  721. self.group_load(self.opt_manager.options['output_format'])
  722. self.title_template_box.SetValue(self.opt_manager.options['output_template'])
  723. self.restrict_filenames_checkbox.SetValue(self.opt_manager.options['restrict_filenames'])
  724. def save_options(self):
  725. self.opt_manager.options['output_format'] = self.get_output_format()
  726. self.opt_manager.options['output_template'] = self.title_template_box.GetValue()
  727. self.opt_manager.options['restrict_filenames'] = self.restrict_filenames_checkbox.GetValue()
  728. class FilesystemPanel(wx.Panel):
  729. win_border = 0
  730. def __init__(self, parent, opt_manager):
  731. wx.Panel.__init__(self, parent)
  732. self.set_win_border()
  733. self.opt_manager = opt_manager
  734. MainBoxSizer = wx.BoxSizer(wx.HORIZONTAL)
  735. LeftBoxSizer = wx.BoxSizer(wx.VERTICAL)
  736. RightBoxSizer = wx.StaticBoxSizer(wx.StaticBox(self, label='Filesize (e.g. 50k or 44.6m)'), wx.VERTICAL)
  737. self.set_left_box(LeftBoxSizer)
  738. self.set_right_box(RightBoxSizer)
  739. MainBoxSizer.Add(LeftBoxSizer, 1, flag=wx.EXPAND | wx.ALL, border=10)
  740. MainBoxSizer.Add(RightBoxSizer, 1, flag=wx.EXPAND | wx.ALL, border=10)
  741. self.SetSizer(MainBoxSizer)
  742. def set_win_border(self):
  743. if os_type == 'nt':
  744. self.win_border = 10
  745. def set_left_box(self, box):
  746. IgnoreErrorsBox = wx.BoxSizer(wx.HORIZONTAL)
  747. self.ignore_errors_checkbox = wx.CheckBox(self, label='Ignore Errors')
  748. IgnoreErrorsBox.Add(self.ignore_errors_checkbox, flag=wx.LEFT, border=5)
  749. box.Add(IgnoreErrorsBox, flag=wx.TOP, border=15)
  750. OpenDirBox = wx.BoxSizer(wx.HORIZONTAL)
  751. self.open_dir_checkbox = wx.CheckBox(self, label='Open download folder')
  752. OpenDirBox.Add(self.open_dir_checkbox, flag=wx.LEFT, border=5)
  753. box.Add(OpenDirBox, flag=wx.TOP, border=5 + self.win_border)
  754. WriteDescBox = wx.BoxSizer(wx.HORIZONTAL)
  755. self.writeDescriptionChk = wx.CheckBox(self, label='Write description to file')
  756. WriteDescBox.Add(self.writeDescriptionChk, flag=wx.LEFT, border=5)
  757. box.Add(WriteDescBox, flag=wx.TOP, border=5 + self.win_border)
  758. WriteInfoBox = wx.BoxSizer(wx.HORIZONTAL)
  759. self.write_info_checkbox = wx.CheckBox(self, label='Write info to (.json) file')
  760. WriteInfoBox.Add(self.write_info_checkbox, flag=wx.LEFT, border=5)
  761. box.Add(WriteInfoBox, flag=wx.TOP, border=5 + self.win_border)
  762. WriteThumnailBox = wx.BoxSizer(wx.HORIZONTAL)
  763. self.write_thumbnail_checkbox = wx.CheckBox(self, label='Write thumbnail to disk')
  764. WriteThumnailBox.Add(self.write_thumbnail_checkbox, flag=wx.LEFT, border=5)
  765. box.Add(WriteThumnailBox, flag=wx.TOP, border=5 + self.win_border)
  766. def set_right_box(self, box):
  767. MinBox = wx.BoxSizer(wx.HORIZONTAL)
  768. MinBox.Add(wx.StaticText(self, label='Min'), flag=wx.RIGHT, border=12)
  769. self.min_filesize_box = wx.TextCtrl(self, size=(80, -1))
  770. MinBox.Add(self.min_filesize_box)
  771. box.Add(MinBox, flag=wx.TOP | wx.ALIGN_CENTER_HORIZONTAL, border=10)
  772. MaxBox = wx.BoxSizer(wx.HORIZONTAL)
  773. MaxBox.Add(wx.StaticText(self, label='Max'), flag=wx.RIGHT, border=8)
  774. self.max_filesize_box = wx.TextCtrl(self, size=(80, -1))
  775. MaxBox.Add(self.max_filesize_box)
  776. box.Add(MaxBox, flag=wx.TOP | wx.ALIGN_CENTER_HORIZONTAL, border=10)
  777. def load_options(self):
  778. self.open_dir_checkbox.SetValue(self.opt_manager.options['open_dl_dir'])
  779. self.min_filesize_box.SetValue(self.opt_manager.options['min_filesize'])
  780. self.max_filesize_box.SetValue(self.opt_manager.options['max_filesize'])
  781. self.write_info_checkbox.SetValue(self.opt_manager.options['write_info'])
  782. self.ignore_errors_checkbox.SetValue(self.opt_manager.options['ignore_errors'])
  783. self.writeDescriptionChk.SetValue(self.opt_manager.options['write_description'])
  784. self.write_thumbnail_checkbox.SetValue(self.opt_manager.options['write_thumbnail'])
  785. def save_options(self):
  786. self.opt_manager.options['write_thumbnail'] = self.write_thumbnail_checkbox.GetValue()
  787. self.opt_manager.options['write_description'] = self.writeDescriptionChk.GetValue()
  788. self.opt_manager.options['ignore_errors'] = self.ignore_errors_checkbox.GetValue()
  789. self.opt_manager.options['write_info'] = self.write_info_checkbox.GetValue()
  790. self.opt_manager.options['open_dl_dir'] = self.open_dir_checkbox.GetValue()
  791. self.opt_manager.options['min_filesize'] = self.min_filesize_box.GetValue()
  792. self.opt_manager.options['max_filesize'] = self.max_filesize_box.GetValue()
  793. self.check_input()
  794. def check_input(self):
  795. self.opt_manager.options['min_filesize'].replace('-', '')
  796. self.opt_manager.options['max_filesize'].replace('-', '')
  797. if self.opt_manager.options['min_filesize'] == '':
  798. self.opt_manager.options['min_filesize'] = '0'
  799. if self.opt_manager.options['max_filesize'] == '':
  800. self.opt_manager.options['max_filesize'] = '0'
  801. class SubtitlesPanel(wx.Panel):
  802. win_border = 0
  803. def __init__(self, parent, opt_manager):
  804. wx.Panel.__init__(self, parent)
  805. self.set_win_border()
  806. self.opt_manager = opt_manager
  807. MainBoxSizer = wx.BoxSizer(wx.VERTICAL)
  808. DLSubtitlesBox = wx.BoxSizer(wx.HORIZONTAL)
  809. self.write_subs_checkbox = wx.CheckBox(self, label='Download subtitle file by language')
  810. DLSubtitlesBox.Add(self.write_subs_checkbox, flag=wx.LEFT, border=10)
  811. MainBoxSizer.Add(DLSubtitlesBox, flag=wx.TOP, border=15)
  812. DLAllSubtitlesBox = wx.BoxSizer(wx.HORIZONTAL)
  813. self.write_all_subs_checkbox = wx.CheckBox(self, label='Download all available subtitles')
  814. DLAllSubtitlesBox.Add(self.write_all_subs_checkbox, flag=wx.LEFT, border=10)
  815. MainBoxSizer.Add(DLAllSubtitlesBox, flag=wx.TOP, border=5 + self.win_border)
  816. DLAutoSubtitlesBox = wx.BoxSizer(wx.HORIZONTAL)
  817. self.write_auto_subs_checkbox = wx.CheckBox(self, label='Download automatic subtitle file (YOUTUBE ONLY)')
  818. DLAutoSubtitlesBox.Add(self.write_auto_subs_checkbox, flag=wx.LEFT, border=10)
  819. MainBoxSizer.Add(DLAutoSubtitlesBox, flag=wx.TOP, border=5 + self.win_border)
  820. EmbedSubtitlesBox = wx.BoxSizer(wx.HORIZONTAL)
  821. self.embed_subs_checkbox = wx.CheckBox(self, label='Embed subtitles in the video (only for mp4 videos)')
  822. self.embed_subs_checkbox.Disable()
  823. EmbedSubtitlesBox.Add(self.embed_subs_checkbox, flag=wx.LEFT, border=10)
  824. MainBoxSizer.Add(EmbedSubtitlesBox, flag=wx.TOP, border=5 + self.win_border)
  825. SubsLanguageTextBox = wx.BoxSizer(wx.HORIZONTAL)
  826. SubsLanguageTextBox.Add(wx.StaticText(self, label='Subtitles Language'), flag=wx.LEFT, border=15)
  827. MainBoxSizer.Add(SubsLanguageTextBox, flag=wx.TOP, border=10 + self.win_border)
  828. SubsLanguageBox = wx.BoxSizer(wx.HORIZONTAL)
  829. self.subs_languages_combo = wx.ComboBox(self, choices=SUBS_LANG, size=(140, 30))
  830. self.subs_languages_combo.Disable()
  831. SubsLanguageBox.Add(self.subs_languages_combo, flag=wx.LEFT, border=10)
  832. MainBoxSizer.Add(SubsLanguageBox, flag=wx.TOP, border=5)
  833. self.SetSizer(MainBoxSizer)
  834. self.Bind(wx.EVT_CHECKBOX, self.OnWriteSubsChk, self.write_subs_checkbox)
  835. self.Bind(wx.EVT_CHECKBOX, self.OnWriteAllSubsChk, self.write_all_subs_checkbox)
  836. self.Bind(wx.EVT_CHECKBOX, self.OnWriteAutoSubsChk, self.write_auto_subs_checkbox)
  837. def set_win_border(self):
  838. if os_type == 'nt':
  839. self.win_border = 5
  840. def OnWriteAutoSubsChk(self, event):
  841. if self.write_auto_subs_checkbox.GetValue():
  842. self.embed_subs_checkbox.Enable()
  843. self.write_subs_checkbox.Disable()
  844. self.write_all_subs_checkbox.Disable()
  845. else:
  846. self.embed_subs_checkbox.Disable()
  847. self.embed_subs_checkbox.SetValue(False)
  848. self.write_subs_checkbox.Enable()
  849. self.write_all_subs_checkbox.Enable()
  850. def OnWriteSubsChk(self, event):
  851. if self.write_subs_checkbox.GetValue():
  852. self.embed_subs_checkbox.Enable()
  853. self.subs_languages_combo.Enable()
  854. self.write_all_subs_checkbox.Disable()
  855. self.write_auto_subs_checkbox.Disable()
  856. else:
  857. self.embed_subs_checkbox.Disable()
  858. self.embed_subs_checkbox.SetValue(False)
  859. self.subs_languages_combo.Disable()
  860. self.write_all_subs_checkbox.Enable()
  861. self.write_auto_subs_checkbox.Enable()
  862. def OnWriteAllSubsChk(self, event):
  863. if self.write_all_subs_checkbox.GetValue():
  864. self.write_subs_checkbox.Disable()
  865. self.write_auto_subs_checkbox.Disable()
  866. else:
  867. self.write_subs_checkbox.Enable()
  868. self.write_auto_subs_checkbox.Enable()
  869. def load_options(self):
  870. self.write_subs_checkbox.SetValue(self.opt_manager.options['write_subs'])
  871. self.subs_languages_combo.SetValue(self.opt_manager.options['subs_lang'])
  872. self.embed_subs_checkbox.SetValue(self.opt_manager.options['embed_subs'])
  873. self.write_all_subs_checkbox.SetValue(self.opt_manager.options['write_all_subs'])
  874. self.write_auto_subs_checkbox.SetValue(self.opt_manager.options['write_auto_subs'])
  875. self.OnWriteSubsChk(None)
  876. self.OnWriteAllSubsChk(None)
  877. self.OnWriteAutoSubsChk(None)
  878. def save_options(self):
  879. self.opt_manager.options['write_subs'] = self.write_subs_checkbox.GetValue()
  880. self.opt_manager.options['subs_lang'] = self.subs_languages_combo.GetValue()
  881. self.opt_manager.options['embed_subs'] = self.embed_subs_checkbox.GetValue()
  882. self.opt_manager.options['write_all_subs'] = self.write_all_subs_checkbox.GetValue()
  883. self.opt_manager.options['write_auto_subs'] = self.write_auto_subs_checkbox.GetValue()
  884. class GeneralPanel(wx.Panel):
  885. def __init__(self, parent, opt_manager, reset_handler):
  886. wx.Panel.__init__(self, parent)
  887. self.opt_manager = opt_manager
  888. self.reset_handler = reset_handler
  889. MainBoxSizer = wx.BoxSizer(wx.VERTICAL)
  890. SavePathTextBox = wx.BoxSizer(wx.HORIZONTAL)
  891. SavePathTextBox.Add(wx.StaticText(self, label='Save Path'))
  892. MainBoxSizer.Add(SavePathTextBox, flag=wx.ALIGN_CENTER_HORIZONTAL | wx.TOP, border=20)
  893. SavePathBox = wx.BoxSizer(wx.HORIZONTAL)
  894. self.savepath_box = wx.TextCtrl(self)
  895. SavePathBox.Add(self.savepath_box, 1, flag=wx.TOP, border=10)
  896. MainBoxSizer.Add(SavePathBox, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=40)
  897. ButtonsBox = wx.BoxSizer(wx.HORIZONTAL)
  898. self.about_button = wx.Button(self, label='About', size=(110, 40))
  899. ButtonsBox.Add(self.about_button)
  900. self.open_button = wx.Button(self, label='Open', size=(110, 40))
  901. ButtonsBox.Add(self.open_button, flag=wx.LEFT | wx.RIGHT, border=50)
  902. self.reset_button = wx.Button(self, label='Reset Options', size=(110, 40))
  903. ButtonsBox.Add(self.reset_button)
  904. MainBoxSizer.Add(ButtonsBox, flag=wx.ALIGN_CENTER_HORIZONTAL | wx.TOP, border=20)
  905. SettingsBox = wx.BoxSizer(wx.HORIZONTAL)
  906. text = 'Settings: ' + self.opt_manager.settings_file
  907. SettingsBox.Add(wx.StaticText(self, label=text), flag=wx.TOP, border=30)
  908. MainBoxSizer.Add(SettingsBox, flag=wx.ALIGN_CENTER_HORIZONTAL)
  909. self.SetSizer(MainBoxSizer)
  910. self.Bind(wx.EVT_BUTTON, self.OnOpen, self.open_button)
  911. self.Bind(wx.EVT_BUTTON, self.OnAbout, self.about_button)
  912. self.Bind(wx.EVT_BUTTON, self.OnReset, self.reset_button)
  913. def OnReset(self, event):
  914. self.reset_handler()
  915. def OnOpen(self, event):
  916. dlg = wx.DirDialog(None, "Choose directory")
  917. if dlg.ShowModal() == wx.ID_OK:
  918. self.savepath_box.SetValue(dlg.GetPath())
  919. dlg.Destroy()
  920. def OnAbout(self, event):
  921. info = wx.AboutDialogInfo()
  922. info.SetIcon(wx.Icon(ICON, wx.BITMAP_TYPE_ICO))
  923. info.SetName(__appname__)
  924. info.SetVersion(__version__)
  925. info.SetDescription(__descriptionfull__)
  926. info.SetWebSite(__projecturl__)
  927. info.SetLicense(__licensefull__)
  928. info.AddDeveloper(__author__)
  929. wx.AboutBox(info)
  930. def load_options(self):
  931. self.savepath_box.SetValue(self.opt_manager.options['save_path'])
  932. def save_options(self):
  933. self.opt_manager.options['save_path'] = fix_path(self.savepath_box.GetValue())
  934. class OtherPanel(wx.Panel):
  935. def __init__(self, parent, opt_manager):
  936. wx.Panel.__init__(self, parent)
  937. self.opt_manager = opt_manager
  938. MainBoxSizer = wx.BoxSizer(wx.VERTICAL)
  939. HelpTextBox = wx.BoxSizer(wx.HORIZONTAL)
  940. HelpTextBox.Add(wx.StaticText(self, label='Command line arguments (e.g. --help)'), flag=wx.TOP, border=30)
  941. MainBoxSizer.Add(HelpTextBox, flag=wx.LEFT, border=50)
  942. CmdInputBox = wx.BoxSizer(wx.HORIZONTAL)
  943. self.cmd_args_box = wx.TextCtrl(self)
  944. CmdInputBox.Add(self.cmd_args_box, 1, flag=wx.TOP, border=10)
  945. MainBoxSizer.Add(CmdInputBox, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=50)
  946. self.SetSizer(MainBoxSizer)
  947. def load_options(self):
  948. self.cmd_args_box.SetValue(self.opt_manager.options['cmd_args'])
  949. def save_options(self):
  950. self.opt_manager.options['cmd_args'] = self.cmd_args_box.GetValue()
  951. class OptionsFrame(wx.Frame):
  952. def __init__(self, opt_manager, parent=None, id=-1, logger=None):
  953. wx.Frame.__init__(self, parent, id, "Options", size=self.get_frame_sizer())
  954. self.opt_manager = opt_manager
  955. panel = wx.Panel(self)
  956. notebook = wx.Notebook(panel)
  957. # Special Tabs
  958. self.general_tab = GeneralPanel(notebook, self.opt_manager, self.reset)
  959. self.log_tab = LogPanel(notebook, self.opt_manager, logger)
  960. # Notebook, OptManager Tabs
  961. self.audio_tab = AudioPanel(notebook, self.opt_manager)
  962. self.video_tab = VideoPanel(notebook, self.opt_manager)
  963. self.other_tab = OtherPanel(notebook, self.opt_manager)
  964. self.output_tab = OutputPanel(notebook, self.opt_manager)
  965. self.playlist_tab = PlaylistPanel(notebook, self.opt_manager)
  966. self.shutdown_tab = ShutdownPanel(notebook, self.opt_manager)
  967. self.subtitles_tab = SubtitlesPanel(notebook, self.opt_manager)
  968. self.auth_tab = AuthenticationPanel(notebook, self.opt_manager)
  969. self.connection_tab = ConnectionPanel(notebook, self.opt_manager)
  970. self.filesystem_tab = FilesystemPanel(notebook, self.opt_manager)
  971. notebook.AddPage(self.general_tab, "General")
  972. notebook.AddPage(self.video_tab, "Video")
  973. notebook.AddPage(self.audio_tab, "Audio")
  974. notebook.AddPage(self.playlist_tab, "Playlist")
  975. notebook.AddPage(self.output_tab, "Output")
  976. notebook.AddPage(self.subtitles_tab, "Subtitles")
  977. notebook.AddPage(self.filesystem_tab, "Filesystem")
  978. notebook.AddPage(self.shutdown_tab, "Shutdown")
  979. notebook.AddPage(self.auth_tab, "Authentication")
  980. notebook.AddPage(self.connection_tab, "Connection")
  981. notebook.AddPage(self.log_tab, "Log")
  982. notebook.AddPage(self.other_tab, "Commands")
  983. sizer = wx.BoxSizer()
  984. sizer.Add(notebook, 1, wx.EXPAND)
  985. panel.SetSizer(sizer)
  986. self.Bind(wx.EVT_CLOSE, self.OnClose)
  987. self.load_all_options()
  988. def get_frame_sizer(self):
  989. if os_type == 'nt':
  990. return (640, 270)
  991. else:
  992. return (640, 250)
  993. def OnClose(self, event):
  994. self.save_all_options()
  995. self.Destroy()
  996. def reset(self):
  997. self.opt_manager.load_default()
  998. self.load_all_options()
  999. def load_all_options(self):
  1000. self.log_tab.load_options()
  1001. self.auth_tab.load_options()
  1002. self.audio_tab.load_options()
  1003. self.video_tab.load_options()
  1004. self.other_tab.load_options()
  1005. self.output_tab.load_options()
  1006. self.general_tab.load_options()
  1007. self.playlist_tab.load_options()
  1008. self.shutdown_tab.load_options()
  1009. self.subtitles_tab.load_options()
  1010. self.connection_tab.load_options()
  1011. self.filesystem_tab.load_options()
  1012. def save_all_options(self):
  1013. self.log_tab.save_options()
  1014. self.auth_tab.save_options()
  1015. self.audio_tab.save_options()
  1016. self.video_tab.save_options()
  1017. self.other_tab.save_options()
  1018. self.output_tab.save_options()
  1019. self.general_tab.save_options()
  1020. self.playlist_tab.save_options()
  1021. self.shutdown_tab.save_options()
  1022. self.subtitles_tab.save_options()
  1023. self.connection_tab.save_options()
  1024. self.filesystem_tab.save_options()