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.

356 lines
13 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
  1. #!/usr/bin/env python2
  2. # -*- coding: utf-8 -*-
  3. """Youtubedlg module to handle settings. """
  4. from __future__ import unicode_literals
  5. import json
  6. import os.path
  7. from .utils import (
  8. os_path_expanduser,
  9. os_path_exists,
  10. encode_tuple,
  11. decode_tuple,
  12. check_path
  13. )
  14. class OptionsManager(object):
  15. """Handles youtubedlg options.
  16. This class is responsible for storing and retrieving the options.
  17. Attributes:
  18. SETTINGS_FILENAME (string): Filename of the settings file.
  19. SENSITIVE_KEYS (tuple): Contains the keys that we don't want
  20. to store on the settings file. (SECURITY ISSUES).
  21. Args:
  22. config_path (string): Absolute path where OptionsManager
  23. should store the settings file.
  24. Note:
  25. See load_default() method for available options.
  26. Example:
  27. Access the options using the 'options' variable.
  28. opt_manager = OptionsManager('.')
  29. opt_manager.options['save_path'] = '~/Downloads'
  30. """
  31. SETTINGS_FILENAME = 'settings.json'
  32. SENSITIVE_KEYS = ('sudo_password', 'password', 'video_password')
  33. def __init__(self, config_path):
  34. self.config_path = config_path
  35. self.settings_file = os.path.join(config_path, self.SETTINGS_FILENAME)
  36. self.options = dict()
  37. self.load_default()
  38. self.load_from_file()
  39. def load_default(self):
  40. """Load the default options.
  41. Note:
  42. This method is automatically called by the constructor.
  43. Options Description:
  44. save_path (string): Path where youtube-dl should store the
  45. downloaded file. Default is $HOME.
  46. video_format (string): Video format to download.
  47. When this options is set to '0' youtube-dl will choose
  48. the best video format available for the given URL.
  49. second_video_format (string): Video format to mix with the first
  50. one (-f 18+17).
  51. to_audio (boolean): If True youtube-dl will post process the
  52. video file.
  53. keep_video (boolen): If True youtube-dl will keep the video file
  54. after post processing it.
  55. audio_format (string): Audio format of the post processed file.
  56. Available values are "mp3", "wav", "aac", "m4a", "vorbis", "opus".
  57. audio_quality (string): Audio quality of the post processed file.
  58. Available values are "9", "5", "0". The lowest the value the
  59. better the quality.
  60. restrict_filenames (boolean): If True youtube-dl will restrict
  61. the downloaded file filename to ASCII characters only.
  62. output_format (string): This option sets the downloaded file
  63. output template. Available values are 'id', 'title', 'custom'
  64. 'id' -> '%(id)s.%(ext)s'
  65. 'title' -> '%(title)s.%(ext)s'
  66. 'custom' -> Use 'output_template' as output template.
  67. output_template (string): Can be any output template supported
  68. by youtube-dl.
  69. playlist_start (int): Playlist index to start downloading.
  70. playlist_end (int): Playlist index to stop downloading.
  71. max_downloads (int): Maximum number of video files to download
  72. from the given playlist.
  73. min_filesize (float): Minimum file size of the video file.
  74. If the video file is smaller than the given size then
  75. youtube-dl will abort the download process.
  76. max_filesize (float): Maximum file size of the video file.
  77. If the video file is larger than the given size then
  78. youtube-dl will abort the download process.
  79. min_filesize_unit (string): Minimum file size unit.
  80. Available values: '', 'k', 'm', 'g', 'y', 'p', 'e', 'z', 'y'.
  81. max_filesize_unit (string): Maximum file size unit.
  82. See 'min_filesize_unit' option for available values.
  83. write_subs (boolean): If True youtube-dl will try to download
  84. the subtitles file for the given URL.
  85. write_all_subs (boolean): If True youtube-dl will try to download
  86. all the available subtitles files for the given URL.
  87. write_auto_subs (boolean): If True youtube-dl will try to download
  88. the automatic subtitles file for the given URL.
  89. embed_subs (boolean): If True youtube-dl will merge the subtitles
  90. file with the video. (ONLY mp4 files).
  91. subs_lang (string): Language of the subtitles file to download.
  92. Needs 'write_subs' option.
  93. ignore_errors (boolean): If True youtube-dl will ignore the errors
  94. and continue the download process.
  95. open_dl_dir (boolean): If True youtube-dlg will open the
  96. destination folder after download process has been completed.
  97. write_description (boolean): If True youtube-dl will write video
  98. description to a .description file.
  99. write_info (boolean): If True youtube-dl will write video
  100. metadata to a .info.json file.
  101. write_thumbnail (boolean): If True youtube-dl will write
  102. thumbnail image to disk.
  103. retries (int): Number of youtube-dl retries.
  104. user_agent (string): Specify a custom user agent for youtube-dl.
  105. referer (string): Specify a custom referer to use if the video
  106. access is restricted to one domain.
  107. proxy (string): Use the specified HTTP/HTTPS proxy.
  108. shutdown (boolean): If True youtube-dlg will turn the computer
  109. off after the download process has been completed.
  110. sudo_password (string): SUDO password for the shutdown process if
  111. the user does not have elevated privileges.
  112. username (string): Username to login with.
  113. password (string): Password to login with.
  114. video_password (string): Video password for the given URL.
  115. youtubedl_path (string): Absolute path to the youtube-dl binary.
  116. Default is the self.config_path. You can change this option
  117. to point on /usr/local/bin etc.. if you want to use the
  118. youtube-dl binary on your system. This is also the directory
  119. where youtube-dlg will auto download the youtube-dl if not
  120. exists so you should make sure you have write access if you
  121. want to update the youtube-dl binary from within youtube-dlg.
  122. cmd_args (string): String that contains extra youtube-dl options
  123. seperated by spaces.
  124. enable_log (boolean): If True youtube-dlg will enable
  125. the LogManager. See main() function under __init__().
  126. log_time (boolean): See logmanager.LogManager add_time attribute.
  127. workers_number (int): Number of download workers that download manager
  128. will spawn. Must be greater than zero.
  129. locale_name (string): Locale name (e.g. ru_RU).
  130. main_win_size (tuple): Main window size (width, height).
  131. If window becomes to small the program will reset its size.
  132. See _settings_are_valid method MIN_FRAME_SIZE.
  133. opts_win_size (tuple): Options window size (width, height).
  134. If window becomes to small the program will reset its size.
  135. See _settings_are_valid method MIN_FRAME_SIZE.
  136. """
  137. self.options = {
  138. 'save_path': os_path_expanduser('~'),
  139. 'video_format': '0',
  140. 'second_video_format': '0',
  141. 'to_audio': False,
  142. 'keep_video': False,
  143. 'audio_format': 'mp3',
  144. 'audio_quality': '5',
  145. 'restrict_filenames': False,
  146. 'output_format': 'title',
  147. 'output_template': '%(uploader)s/%(title)s.%(ext)s',
  148. 'playlist_start': 1,
  149. 'playlist_end': 0,
  150. 'max_downloads': 0,
  151. 'min_filesize': 0,
  152. 'max_filesize': 0,
  153. 'min_filesize_unit': '',
  154. 'max_filesize_unit': '',
  155. 'write_subs': False,
  156. 'write_all_subs': False,
  157. 'write_auto_subs': False,
  158. 'embed_subs': False,
  159. 'subs_lang': 'en',
  160. 'ignore_errors': True,
  161. 'open_dl_dir': True,
  162. 'write_description': False,
  163. 'write_info': False,
  164. 'write_thumbnail': False,
  165. 'retries': 10,
  166. 'user_agent': '',
  167. 'referer': '',
  168. 'proxy': '',
  169. 'shutdown': False,
  170. 'sudo_password': '',
  171. 'username': '',
  172. 'password': '',
  173. 'video_password': '',
  174. 'youtubedl_path': self.config_path,
  175. 'cmd_args': '',
  176. 'enable_log': True,
  177. 'log_time': False,
  178. 'workers_number': 3,
  179. 'locale_name': 'en_US',
  180. 'main_win_size': (710, 490),
  181. 'opts_win_size': (640, 270)
  182. }
  183. def load_from_file(self):
  184. """Load options from settings file. """
  185. if not os_path_exists(self.settings_file):
  186. return
  187. with open(self.settings_file, 'rb') as settings_file:
  188. try:
  189. options = json.load(settings_file)
  190. if self._settings_are_valid(options):
  191. self.options = options
  192. except:
  193. self.load_default()
  194. def save_to_file(self):
  195. """Save options to settings file. """
  196. check_path(self.config_path)
  197. with open(self.settings_file, 'wb') as settings_file:
  198. options = self._get_options()
  199. json.dump(options,
  200. settings_file,
  201. indent=4,
  202. separators=(',', ': '))
  203. def _settings_are_valid(self, settings_dictionary):
  204. """Check settings.json dictionary.
  205. Args:
  206. settings_dictionary (dict): Options dictionary loaded
  207. from the settings file. See load_from_file() method.
  208. Returns:
  209. True if settings.json dictionary is valid, else False.
  210. """
  211. VALID_VIDEO_FORMAT = ('0', '17', '36', '5', '34', '35', '43', '44', '45',
  212. '46', '18', '22', '37', '38', '160', '133', '134', '135', '136','137',
  213. '264', '138', '242', '243', '244', '247', '248', '271', '272', '82',
  214. '83', '84', '85', '100', '101', '102', '139', '140', '141', '171', '172')
  215. VALID_AUDIO_FORMAT = ('mp3', 'wav', 'aac', 'm4a', 'vorbis', 'opus')
  216. VALID_AUDIO_QUALITY = ('0', '5', '9')
  217. VALID_OUTPUT_FORMAT = ('title', 'id', 'custom')
  218. VALID_FILESIZE_UNIT = ('', 'k', 'm', 'g', 't', 'p', 'e', 'z', 'y')
  219. VALID_SUB_LANGUAGE = ('en', 'gr', 'pt', 'fr', 'it', 'ru', 'es', 'de')
  220. MIN_FRAME_SIZE = 100
  221. # Decode string formatted tuples back to normal tuples
  222. settings_dictionary['main_win_size'] = decode_tuple(settings_dictionary['main_win_size'])
  223. settings_dictionary['opts_win_size'] = decode_tuple(settings_dictionary['opts_win_size'])
  224. for key in self.options:
  225. if key not in settings_dictionary:
  226. return False
  227. if type(self.options[key]) != type(settings_dictionary[key]):
  228. return False
  229. # Check if each key has a valid value
  230. rules_dict = {
  231. 'video_format': VALID_VIDEO_FORMAT,
  232. 'second_video_format': VALID_VIDEO_FORMAT,
  233. 'audio_format': VALID_AUDIO_FORMAT,
  234. 'audio_quality': VALID_AUDIO_QUALITY,
  235. 'output_format': VALID_OUTPUT_FORMAT,
  236. 'min_filesize_unit': VALID_FILESIZE_UNIT,
  237. 'max_filesize_unit': VALID_FILESIZE_UNIT,
  238. 'subs_lang': VALID_SUB_LANGUAGE
  239. }
  240. for key, valid_list in rules_dict.items():
  241. if settings_dictionary[key] not in valid_list:
  242. return False
  243. # Check workers number value
  244. if settings_dictionary['workers_number'] < 1:
  245. return False
  246. # Check main-options frame size
  247. for size in settings_dictionary['main_win_size']:
  248. if size < MIN_FRAME_SIZE:
  249. return False
  250. for size in settings_dictionary['opts_win_size']:
  251. if size < MIN_FRAME_SIZE:
  252. return False
  253. return True
  254. def _get_options(self):
  255. """Return options dictionary without SENSITIVE_KEYS. """
  256. temp_options = self.options.copy()
  257. for key in self.SENSITIVE_KEYS:
  258. temp_options[key] = ''
  259. # Encode normal tuples to string formatted tuples
  260. temp_options['main_win_size'] = encode_tuple(temp_options['main_win_size'])
  261. temp_options['opts_win_size'] = encode_tuple(temp_options['opts_win_size'])
  262. return temp_options