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.

243 lines
9.5 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
  1. #!/usr/bin/env python2
  2. # -*- coding: utf-8 -*-
  3. """Youtubedlg module responsible for parsing the options. """
  4. from __future__ import unicode_literals
  5. import os.path
  6. from .utils import (
  7. remove_shortcuts,
  8. to_string
  9. )
  10. class OptionHolder(object):
  11. """Simple data structure that holds informations for the given option.
  12. Args:
  13. name (string): Option name. Must be a valid option name
  14. from the optionsmanager.OptionsManager class.
  15. See optionsmanager.OptionsManager load_default() method.
  16. flag (string): The option command line switch.
  17. See https://github.com/rg3/youtube-dl/#options
  18. default_value (any): The option default value. Must be the same type
  19. with the corresponding option from the optionsmanager.OptionsManager
  20. class.
  21. requirements (list): The requirements for the given option. This
  22. argument is a list of strings with the name of all the options
  23. that this specific option needs. For example 'subs_lang' needs the
  24. 'write_subs' option to be enabled.
  25. """
  26. def __init__(self, name, flag, default_value, requirements=None):
  27. self.name = name
  28. self.flag = flag
  29. self.requirements = requirements
  30. self.default_value = default_value
  31. def is_boolean(self):
  32. """Returns True if the option is a boolean switch else False. """
  33. return type(self.default_value) is bool
  34. def check_requirements(self, options_dict):
  35. """Check if the required options are enabled.
  36. Args:
  37. options_dict (dict): Dictionary with all the options.
  38. Returns:
  39. True if any of the required options is enabled else False.
  40. """
  41. if self.requirements is None:
  42. return True
  43. return any([options_dict[req] for req in self.requirements])
  44. class OptionsParser(object):
  45. """Parse optionsmanager.OptionsManager options.
  46. This class is responsible for turning some of the youtube-dlg options
  47. to youtube-dl command line options.
  48. """
  49. def __init__(self):
  50. self._ydl_options = [
  51. OptionHolder('playlist_start', '--playlist-start', 1),
  52. OptionHolder('playlist_end', '--playlist-end', 0),
  53. OptionHolder('max_downloads', '--max-downloads', 0),
  54. OptionHolder('username', '-u', ''),
  55. OptionHolder('password', '-p', ''),
  56. OptionHolder('video_password', '--video-password', ''),
  57. OptionHolder('retries', '-R', 10),
  58. OptionHolder('proxy', '--proxy', ''),
  59. OptionHolder('user_agent', '--user-agent', ''),
  60. OptionHolder('referer', '--referer', ''),
  61. OptionHolder('ignore_errors', '-i', False),
  62. OptionHolder('write_description', '--write-description', False),
  63. OptionHolder('write_info', '--write-info-json', False),
  64. OptionHolder('write_thumbnail', '--write-thumbnail', False),
  65. OptionHolder('min_filesize', '--min-filesize', 0),
  66. OptionHolder('max_filesize', '--max-filesize', 0),
  67. OptionHolder('write_all_subs', '--all-subs', False),
  68. OptionHolder('write_auto_subs', '--write-auto-sub', False),
  69. OptionHolder('write_subs', '--write-sub', False),
  70. OptionHolder('keep_video', '-k', False),
  71. OptionHolder('restrict_filenames', '--restrict-filenames', False),
  72. OptionHolder('save_path', '-o', ''),
  73. OptionHolder('embed_subs', '--embed-subs', False, ['write_auto_subs', 'write_subs']),
  74. OptionHolder('to_audio', '-x', False),
  75. OptionHolder('audio_format', '--audio-format', ''),
  76. OptionHolder('video_format', '-f', '0'),
  77. OptionHolder('subs_lang', '--sub-lang', '', ['write_subs']),
  78. OptionHolder('audio_quality', '--audio-quality', '5', ['to_audio']),
  79. OptionHolder('youtube_dl_debug', '-v', False),
  80. OptionHolder('ignore_config', '--ignore-config', False),
  81. OptionHolder('native_hls', '--hls-prefer-native', False),
  82. OptionHolder('nomtime', '--no-mtime', False),
  83. OptionHolder('embed_thumbnail', '--embed-thumbnail', False),
  84. OptionHolder('add_metadata', '--add-metadata', False)
  85. ]
  86. def parse(self, options_dictionary):
  87. """Parse optionsmanager.OptionsManager options.
  88. Parses the given options to youtube-dl command line arguments.
  89. Args:
  90. options_dictionary (dict): Dictionary with all the options.
  91. Returns:
  92. List of strings with all the youtube-dl command line options.
  93. """
  94. options_list = ['--newline']
  95. # Create a copy of options_dictionary
  96. # We don't want to edit the original options dictionary
  97. # and change some of the options values like 'save_path' etc..
  98. options_dict = options_dictionary.copy()
  99. self._build_savepath(options_dict)
  100. self._build_videoformat(options_dict)
  101. self._build_filesizes(options_dict)
  102. # Parse basic youtube-dl command line options
  103. for option in self._ydl_options:
  104. #NOTE Special case should be removed
  105. if option.name == "to_audio":
  106. if options_dict["audio_format"] == "":
  107. value = options_dict[option.name]
  108. if value != option.default_value:
  109. options_list.append(option.flag)
  110. elif option.name == "audio_format":
  111. value = options_dict[option.name]
  112. if value != option.default_value:
  113. options_list.append("-x")
  114. options_list.append(option.flag)
  115. options_list.append(to_string(value))
  116. #NOTE Temp fix
  117. # If current 'audio_quality' is not the default one ('5')
  118. # then append the audio quality flag and value to the
  119. # options list
  120. if options_dict["audio_quality"] != "5":
  121. options_list.append("--audio-quality")
  122. options_list.append(to_string(options_dict["audio_quality"]))
  123. elif option.name == "audio_quality":
  124. # If the '--audio-quality' is not already in the options list
  125. # from the above branch then follow the standard procedure.
  126. # We don't have to worry for the sequence in which the code
  127. # will be executed since the 'audio_quality' option is placed
  128. # after the 'audio_format' option in the self._ydl_options list
  129. if option.flag not in options_list:
  130. if option.check_requirements(options_dict):
  131. value = options_dict[option.name]
  132. if value != option.default_value:
  133. options_list.append(option.flag)
  134. options_list.append(to_string(value))
  135. elif option.check_requirements(options_dict):
  136. value = options_dict[option.name]
  137. if value != option.default_value:
  138. options_list.append(option.flag)
  139. if not option.is_boolean():
  140. options_list.append(to_string(value))
  141. # Parse cmd_args
  142. for option in options_dict['cmd_args'].split():
  143. options_list.append(option)
  144. return options_list
  145. def _build_savepath(self, options_dict):
  146. """Build the save path.
  147. We use this method to build the value of the 'save_path' option and
  148. store it back to the options dictionary.
  149. Args:
  150. options_dict (dict): Copy of the original options dictionary.
  151. """
  152. save_path = remove_shortcuts(options_dict['save_path'])
  153. if options_dict["output_format"] == 0:
  154. template = "%(id)s.%(ext)s"
  155. elif options_dict["output_format"] == 1:
  156. template = "%(title)s.%(ext)s"
  157. elif options_dict["output_format"] == 2:
  158. template = "%(title)s-%(id)s.%(ext)s"
  159. elif options_dict["output_format"] == 4:
  160. template = "%(title)s-%(height)sp.%(ext)s"
  161. elif options_dict["output_format"] == 5:
  162. template = "%(title)s-%(id)s-%(height)sp.%(ext)s"
  163. else:
  164. template = options_dict["output_template"]
  165. options_dict["save_path"] = os.path.join(save_path, template)
  166. def _build_videoformat(self, options_dict):
  167. """Build the video format.
  168. We use this method to build the value of the 'video_format' option and
  169. store it back to the options dictionary.
  170. Args:
  171. options_dict (dict): Copy of the original options dictionary.
  172. """
  173. if options_dict['video_format'] != '0' and options_dict['second_video_format'] != '0':
  174. options_dict['video_format'] = options_dict['video_format'] + '+' + options_dict['second_video_format']
  175. def _build_filesizes(self, options_dict):
  176. """Build the filesize options values.
  177. We use this method to build the values of 'min_filesize' and
  178. 'max_filesize' options and store them back to options dictionary.
  179. Args:
  180. options_dict (dict): Copy of the original options dictionary.
  181. """
  182. if options_dict['min_filesize']:
  183. options_dict['min_filesize'] = to_string(options_dict['min_filesize']) + options_dict['min_filesize_unit']
  184. if options_dict['max_filesize']:
  185. options_dict['max_filesize'] = to_string(options_dict['max_filesize']) + options_dict['max_filesize_unit']