youtube-dl-gui/youtube_dl_gui/parsers.py

270 lines
10 KiB
Python

#!/usr/bin/env python2
# -*- coding: utf-8 -*-
"""Youtubedlg module responsible for parsing the options. """
from __future__ import unicode_literals
import os.path
from .utils import (
remove_shortcuts,
to_string
)
class OptionHolder(object):
"""Simple data structure that holds informations for the given option.
Args:
name (string): Option name. Must be a valid option name
from the optionsmanager.OptionsManager class.
See optionsmanager.OptionsManager load_default() method.
flag (string): The option command line switch.
See https://github.com/rg3/youtube-dl/#options
default_value (any): The option default value. Must be the same type
with the corresponding option from the optionsmanager.OptionsManager
class.
requirements (list): The requirements for the given option. This
argument is a list of strings with the name of all the options
that this specific option needs. For example 'subs_lang' needs the
'write_subs' option to be enabled.
"""
def __init__(self, name, flag, default_value, requirements=None):
self.name = name
self.flag = flag
self.requirements = requirements
self.default_value = default_value
def is_boolean(self):
"""Returns True if the option is a boolean switch else False. """
return type(self.default_value) is bool
def check_requirements(self, options_dict):
"""Check if the required options are enabled.
Args:
options_dict (dict): Dictionary with all the options.
Returns:
True if any of the required options is enabled else False.
"""
if self.requirements is None:
return True
return any([options_dict[req] for req in self.requirements])
class OptionsParser(object):
"""Parse optionsmanager.OptionsManager options.
This class is responsible for turning some of the youtube-dlg options
to youtube-dl command line options.
"""
def __init__(self):
self._ydl_options = [
OptionHolder('playlist_start', '--playlist-start', 1),
OptionHolder('playlist_end', '--playlist-end', 0),
OptionHolder('max_downloads', '--max-downloads', 0),
OptionHolder('username', '-u', ''),
OptionHolder('password', '-p', ''),
OptionHolder('video_password', '--video-password', ''),
OptionHolder('retries', '-R', 10),
OptionHolder('proxy', '--proxy', ''),
OptionHolder('user_agent', '--user-agent', ''),
OptionHolder('referer', '--referer', ''),
OptionHolder('ignore_errors', '-i', False),
OptionHolder('write_description', '--write-description', False),
OptionHolder('write_info', '--write-info-json', False),
OptionHolder('write_thumbnail', '--write-thumbnail', False),
OptionHolder('min_filesize', '--min-filesize', 0),
OptionHolder('max_filesize', '--max-filesize', 0),
OptionHolder('write_all_subs', '--all-subs', False),
OptionHolder('write_auto_subs', '--write-auto-sub', False),
OptionHolder('write_subs', '--write-sub', False),
OptionHolder('keep_video', '-k', False),
OptionHolder('restrict_filenames', '--restrict-filenames', False),
OptionHolder('save_path', '-o', ''),
OptionHolder('embed_subs', '--embed-subs', False, ['write_auto_subs', 'write_subs']),
OptionHolder('to_audio', '-x', False),
OptionHolder('audio_format', '--audio-format', ''),
OptionHolder('video_format', '-f', '0'),
OptionHolder('subs_lang', '--sub-lang', '', ['write_subs']),
OptionHolder('audio_quality', '--audio-quality', '5', ['to_audio']),
OptionHolder('youtube_dl_debug', '-v', False),
OptionHolder('ignore_config', '--ignore-config', False),
OptionHolder('native_hls', '--hls-prefer-native', False),
OptionHolder('nomtime', '--no-mtime', False),
OptionHolder('embed_thumbnail', '--embed-thumbnail', False),
OptionHolder('add_metadata', '--add-metadata', False)
]
def parse(self, options_dictionary):
"""Parse optionsmanager.OptionsManager options.
Parses the given options to youtube-dl command line arguments.
Args:
options_dictionary (dict): Dictionary with all the options.
Returns:
List of strings with all the youtube-dl command line options.
"""
# REFACTOR
options_list = ['--newline']
# Create a copy of options_dictionary
# We don't want to edit the original options dictionary
# and change some of the options values like 'save_path' etc..
options_dict = options_dictionary.copy()
self._build_savepath(options_dict)
self._build_videoformat(options_dict)
self._build_filesizes(options_dict)
# Parse basic youtube-dl command line options
for option in self._ydl_options:
#NOTE Special case should be removed
if option.name == "to_audio":
if options_dict["audio_format"] == "":
value = options_dict[option.name]
if value != option.default_value:
options_list.append(option.flag)
elif option.name == "audio_format":
value = options_dict[option.name]
if value != option.default_value:
options_list.append("-x")
options_list.append(option.flag)
options_list.append(to_string(value))
#NOTE Temp fix
# If current 'audio_quality' is not the default one ('5')
# then append the audio quality flag and value to the
# options list
if options_dict["audio_quality"] != "5":
options_list.append("--audio-quality")
options_list.append(to_string(options_dict["audio_quality"]))
elif option.name == "audio_quality":
# If the '--audio-quality' is not already in the options list
# from the above branch then follow the standard procedure.
# We don't have to worry for the sequence in which the code
# will be executed since the 'audio_quality' option is placed
# after the 'audio_format' option in the self._ydl_options list
if option.flag not in options_list:
if option.check_requirements(options_dict):
value = options_dict[option.name]
if value != option.default_value:
options_list.append(option.flag)
options_list.append(to_string(value))
elif option.check_requirements(options_dict):
value = options_dict[option.name]
if value != option.default_value:
options_list.append(option.flag)
if not option.is_boolean():
options_list.append(to_string(value))
# Parse cmd_args
# Indicates whether an item needs special handling
special_case = False
# Temp list to hold special items
special_items = []
for item in options_dict["cmd_args"].split():
# Its a special case if its already a special case
# or an item starts with double quotes
special_case = (special_case or item[0] == "\"")
if special_case:
special_items.append(item)
else:
options_list.append(item)
# If its a special case and we meet a double quote
# at the end of the item, special case is over and
# we need to join, filter and append our special items
# to the options list
if special_case and item[-1] == "\"":
options_list.append(" ".join(special_items)[1:-1])
special_case = False
special_items = []
return options_list
def _build_savepath(self, options_dict):
"""Build the save path.
We use this method to build the value of the 'save_path' option and
store it back to the options dictionary.
Args:
options_dict (dict): Copy of the original options dictionary.
"""
save_path = remove_shortcuts(options_dict['save_path'])
if options_dict["output_format"] == 0:
template = "%(id)s.%(ext)s"
elif options_dict["output_format"] == 1:
template = "%(title)s.%(ext)s"
elif options_dict["output_format"] == 2:
template = "%(title)s-%(id)s.%(ext)s"
elif options_dict["output_format"] == 4:
template = "%(title)s-%(height)sp.%(ext)s"
elif options_dict["output_format"] == 5:
template = "%(title)s-%(id)s-%(height)sp.%(ext)s"
else:
template = options_dict["output_template"]
options_dict["save_path"] = os.path.join(save_path, template)
def _build_videoformat(self, options_dict):
"""Build the video format.
We use this method to build the value of the 'video_format' option and
store it back to the options dictionary.
Args:
options_dict (dict): Copy of the original options dictionary.
"""
if options_dict['video_format'] != '0' and options_dict['second_video_format'] != '0':
options_dict['video_format'] = options_dict['video_format'] + '+' + options_dict['second_video_format']
def _build_filesizes(self, options_dict):
"""Build the filesize options values.
We use this method to build the values of 'min_filesize' and
'max_filesize' options and store them back to options dictionary.
Args:
options_dict (dict): Copy of the original options dictionary.
"""
if options_dict['min_filesize']:
options_dict['min_filesize'] = to_string(options_dict['min_filesize']) + options_dict['min_filesize_unit']
if options_dict['max_filesize']:
options_dict['max_filesize'] = to_string(options_dict['max_filesize']) + options_dict['max_filesize_unit']