compat_shlex_split,
)
from .utils import (
+ expand_path,
+ get_executable_path,
+ OUTTMPL_TYPES,
preferredencoding,
+ REMUX_EXTENSIONS,
write_string,
)
from .version import __version__
userConfFile = os.path.join(xdg_config_home, '%s.conf' % package_name)
userConf = _readOptions(userConfFile, default=None)
if userConf is not None:
- return userConf
+ return userConf, userConfFile
# appdata
appdata_dir = compat_getenv('appdata')
userConfFile = os.path.join(appdata_dir, package_name, 'config')
userConf = _readOptions(userConfFile, default=None)
if userConf is None:
- userConf = _readOptions('%s.txt' % userConfFile, default=None)
+ userConfFile += '.txt'
+ userConf = _readOptions(userConfFile, default=None)
if userConf is not None:
- return userConf
+ return userConf, userConfFile
# home
userConfFile = os.path.join(compat_expanduser('~'), '%s.conf' % package_name)
userConf = _readOptions(userConfFile, default=None)
if userConf is None:
- userConf = _readOptions('%s.txt' % userConfFile, default=None)
+ userConfFile += '.txt'
+ userConf = _readOptions(userConfFile, default=None)
if userConf is not None:
- return userConf
+ return userConf, userConfFile
- return default
+ return default, None
def _format_option_string(option):
''' ('-o', '--option') -> -o, --format METAVAR'''
general.add_option(
'--config-location',
dest='config_location', metavar='PATH',
- help='Location of the configuration file; either the path to the config or its containing directory')
+ help='Location of the main configuration file; either the path to the config or its containing directory')
general.add_option(
'--flat-playlist',
action='store_const', dest='extract_flat', const='in_playlist', default=False,
metavar='NAME:ARGS', dest='external_downloader_args', default={}, type='str',
action='callback', callback=_dict_from_multiple_values_options_callback,
callback_kwargs={
- 'allowed_keys': '|'.join(list_external_downloaders()),
+ 'allowed_keys': '|'.join(list_external_downloaders()),
'default_key': 'default', 'process': compat_shlex_split},
help=(
'Give these arguments to the external downloader. '
filesystem.add_option(
'--id', default=False,
action='store_true', dest='useid', help=optparse.SUPPRESS_HELP)
+ filesystem.add_option(
+ '-P', '--paths',
+ metavar='TYPE:PATH', dest='paths', default={}, type='str',
+ action='callback', callback=_dict_from_multiple_values_options_callback,
+ callback_kwargs={
+ 'allowed_keys': 'home|temp|%s' % '|'.join(OUTTMPL_TYPES.keys()),
+ 'process': lambda x: x.strip()},
+ help=(
+ 'The paths where the files should be downloaded. '
+ 'Specify the type of file and the path separated by a colon ":". '
+ 'All the same types as --output are supported. '
+ 'Additionally, you can also provide "home" and "temp" paths. '
+ 'All intermediary files are first downloaded to the temp path and '
+ 'then the final files are moved over to the home path after download is finished. '
+ 'This option is ignored if --output is an absolute path'))
filesystem.add_option(
'-o', '--output',
- dest='outtmpl', metavar='TEMPLATE',
+ metavar='[TYPE:]TEMPLATE', dest='outtmpl', default={}, type='str',
+ action='callback', callback=_dict_from_multiple_values_options_callback,
+ callback_kwargs={
+ 'allowed_keys': '|'.join(OUTTMPL_TYPES.keys()),
+ 'default_key': 'default', 'process': lambda x: x.strip()},
help='Output filename template, see "OUTPUT TEMPLATE" for details')
+ filesystem.add_option(
+ '--output-na-placeholder',
+ dest='outtmpl_na_placeholder', metavar='TEXT', default='NA',
+ help=('Placeholder value for unavailable meta fields in output filename template (default: "%default")'))
filesystem.add_option(
'--autonumber-size',
dest='autonumber_size', metavar='NUMBER', type=int,
filesystem.add_option(
'-c', '--continue',
action='store_true', dest='continue_dl', default=True,
- help='Resume partially downloaded files (default)')
+ help='Resume partially downloaded files/fragments (default)')
filesystem.add_option(
'--no-continue',
action='store_false', dest='continue_dl',
- help='Restart download of partially downloaded files from beginning')
+ help=(
+ 'Do not resume partially downloaded fragments. '
+ 'If the file is unfragmented, restart download of the entire file'))
filesystem.add_option(
'--part',
action='store_false', dest='nopart', default=False,
filesystem.add_option(
'--write-info-json',
action='store_true', dest='writeinfojson', default=False,
- help='Write video metadata to a .info.json file')
+ help='Write video metadata to a .info.json file (this may contain personal information)')
filesystem.add_option(
'--no-write-info-json',
action='store_false', dest='writeinfojson',
'--no-write-annotations',
action='store_false', dest='writeannotations',
help='Do not write video annotations (default)')
+ filesystem.add_option(
+ '--write-playlist-metafiles',
+ action='store_true', dest='allow_playlist_files', default=True,
+ help=(
+ 'Write playlist metadata in addition to the video metadata '
+ 'when using --write-info-json, --write-description etc. (default)'))
+ filesystem.add_option(
+ '--no-write-playlist-metafiles',
+ action='store_false', dest='allow_playlist_files',
+ help=(
+ 'Do not write playlist metadata when using '
+ '--write-info-json, --write-description etc.'))
+ filesystem.add_option(
+ '--get-comments',
+ action='store_true', dest='getcomments', default=False,
+ help='Retrieve video comments to be placed in the .info.json file')
filesystem.add_option(
'--load-info-json', '--load-info',
dest='load_info_filename', metavar='FILE',
postproc.add_option(
'-x', '--extract-audio',
action='store_true', dest='extractaudio', default=False,
- help='Convert video files to audio-only files (requires ffmpeg or avconv and ffprobe or avprobe)')
+ help='Convert video files to audio-only files (requires ffmpeg and ffprobe)')
postproc.add_option(
'--audio-format', metavar='FORMAT', dest='audioformat', default='best',
help='Specify audio format: "best", "aac", "flac", "mp3", "m4a", "opus", "vorbis", or "wav"; "%default" by default; No effect without -x')
postproc.add_option(
'--audio-quality', metavar='QUALITY',
dest='audioquality', default='5',
- help='Specify ffmpeg/avconv audio quality, insert a value between 0 (better) and 9 (worse) for VBR or a specific bitrate like 128K (default %default)')
+ help='Specify ffmpeg audio quality, insert a value between 0 (better) and 9 (worse) for VBR or a specific bitrate like 128K (default %default)')
postproc.add_option(
'--remux-video',
metavar='FORMAT', dest='remuxvideo', default=None,
help=(
- 'Remux the video into another container if necessary (currently supported: mp4|mkv). '
- 'If target container does not support the video/audio codec, remuxing will fail'))
+ 'Remux the video into another container if necessary (currently supported: %s). '
+ 'If target container does not support the video/audio codec, remuxing will fail. '
+ 'You can specify multiple rules; eg. "aac>m4a/mov>mp4/mkv" will remux aac to m4a, mov to mp4 '
+ 'and anything else to mkv.' % '|'.join(REMUX_EXTENSIONS)))
postproc.add_option(
'--recode-video',
metavar='FORMAT', dest='recodevideo', default=None,
- help='Re-encode the video into another format if re-encoding is necessary (currently supported: mp4|flv|ogg|webm|mkv|avi)')
+ help=(
+ 'Re-encode the video into another format if re-encoding is necessary. '
+ 'The supported formats are the same as --remux-video'))
postproc.add_option(
'--postprocessor-args', '--ppa',
metavar='NAME:ARGS', dest='postprocessor_args', default={}, type='str',
'to give the argument to the specified postprocessor/executable. Supported postprocessors are: '
'SponSkrub, ExtractAudio, VideoRemuxer, VideoConvertor, EmbedSubtitle, Metadata, Merger, '
'FixupStretched, FixupM4a, FixupM3u8, SubtitlesConvertor and EmbedThumbnail. '
- 'The supported executables are: SponSkrub, FFmpeg, FFprobe, avconf, avprobe and AtomicParsley. '
+ 'The supported executables are: SponSkrub, FFmpeg, FFprobe, and AtomicParsley. '
'You can use this option multiple times to give different arguments to different postprocessors. '
'You can also specify "PP+EXE:ARGS" to give the arguments to the specified executable '
'only when being used by the specified postprocessor. '
postproc.add_option(
'--metadata-from-title',
metavar='FORMAT', dest='metafromtitle',
+ help=optparse.SUPPRESS_HELP)
+ postproc.add_option(
+ '--parse-metadata',
+ metavar='FIELD:FORMAT', dest='metafromfield', action='append',
help=(
- 'Parse additional metadata like song title / artist from the video title. '
- 'The format syntax is the same as --output. Regular expression with '
- 'named capture groups may also be used. '
- 'The parsed parameters replace existing values. '
- 'Example: --metadata-from-title "%(artist)s - %(title)s" matches a title like '
+ 'Parse additional metadata like title/artist from other fields. '
+ 'Give field name to extract data from, and format of the field seperated by a ":". '
+ 'Either regular expression with named capture groups or a '
+ 'similar syntax to the output template can also be used. '
+ 'The parsed parameters replace any existing values and can be use in output template'
+ 'This option can be used multiple times. '
+ 'Example: --parse-metadata "title:%(artist)s - %(title)s" matches a title like '
'"Coldplay - Paradise". '
- 'Example (regex): --metadata-from-title "(?P<artist>.+?) - (?P<title>.+)"'))
+ 'Example (regex): --parse-metadata "description:Artist - (?P<artist>.+?)"'))
postproc.add_option(
'--xattrs',
action='store_true', dest='xattrs', default=False,
postproc.add_option(
'--prefer-avconv', '--no-prefer-ffmpeg',
action='store_false', dest='prefer_ffmpeg',
- help='Prefer avconv over ffmpeg for running the postprocessors (Alias: --no-prefer-ffmpeg)')
+ help=optparse.SUPPRESS_HELP)
postproc.add_option(
'--prefer-ffmpeg', '--no-prefer-avconv',
- action='store_true', dest='prefer_ffmpeg',
- help='Prefer ffmpeg over avconv for running the postprocessors (default) (Alias: --no-prefer-avconv)')
+ action='store_true', dest='prefer_ffmpeg', default=True,
+ help=optparse.SUPPRESS_HELP)
postproc.add_option(
'--ffmpeg-location', '--avconv-location', metavar='PATH',
dest='ffmpeg_location',
- help='Location of the ffmpeg/avconv binary; either the path to the binary or its containing directory (Alias: --avconv-location)')
+ help='Location of the ffmpeg binary; either the path to the binary or its containing directory')
postproc.add_option(
'--exec',
metavar='CMD', dest='exec_cmd',
return conf
configs = {
- 'command_line': compat_conf(sys.argv[1:]),
- 'custom': [], 'portable': [], 'user': [], 'system': []}
- opts, args = parser.parse_args(configs['command_line'])
+ 'command-line': compat_conf(sys.argv[1:]),
+ 'custom': [], 'home': [], 'portable': [], 'user': [], 'system': []}
+ paths = {'command-line': False}
+ opts, args = parser.parse_args(configs['command-line'])
def get_configs():
- if '--config-location' in configs['command_line']:
+ if '--config-location' in configs['command-line']:
location = compat_expanduser(opts.config_location)
if os.path.isdir(location):
location = os.path.join(location, 'youtube-dlc.conf')
if not os.path.exists(location):
parser.error('config-location %s does not exist.' % location)
- configs['custom'] = _readOptions(location)
-
- if '--ignore-config' in configs['command_line']:
+ configs['custom'] = _readOptions(location, default=None)
+ if configs['custom'] is None:
+ configs['custom'] = []
+ else:
+ paths['custom'] = location
+ if '--ignore-config' in configs['command-line']:
return
if '--ignore-config' in configs['custom']:
return
- def get_portable_path():
- path = os.path.dirname(sys.argv[0])
- if os.path.abspath(sys.argv[0]) != os.path.abspath(sys.executable): # Not packaged
- path = os.path.join(path, '..')
- return os.path.abspath(path)
-
- run_path = get_portable_path()
- configs['portable'] = _readOptions(os.path.join(run_path, 'yt-dlp.conf'), default=None)
- if configs['portable'] is None:
- configs['portable'] = _readOptions(os.path.join(run_path, 'youtube-dlc.conf'))
+ def read_options(path, user=False):
+ for package in ('yt-dlp', 'youtube-dlc'):
+ if user:
+ config, current_path = _readUserConf(package, default=None)
+ else:
+ current_path = os.path.join(path, '%s.conf' % package)
+ config = _readOptions(current_path, default=None)
+ if config is not None:
+ return config, current_path
+ return [], None
+ configs['portable'], paths['portable'] = read_options(get_executable_path())
if '--ignore-config' in configs['portable']:
return
- configs['system'] = _readOptions('/etc/yt-dlp.conf', default=None)
- if configs['system'] is None:
- configs['system'] = _readOptions('/etc/youtube-dlc.conf')
+ def get_home_path():
+ opts = parser.parse_args(configs['portable'] + configs['custom'] + configs['command-line'])[0]
+ return expand_path(opts.paths.get('home', '')).strip()
+
+ configs['home'], paths['home'] = read_options(get_home_path())
+ if '--ignore-config' in configs['home']:
+ return
+
+ configs['system'], paths['system'] = read_options('/etc')
if '--ignore-config' in configs['system']:
return
- configs['user'] = _readUserConf('yt-dlp', default=None)
- if configs['user'] is None:
- configs['user'] = _readUserConf('youtube-dlc')
+
+ configs['user'], paths['user'] = read_options('', True)
if '--ignore-config' in configs['user']:
- configs['system'] = []
+ configs['system'], paths['system'] = [], None
get_configs()
- argv = configs['system'] + configs['user'] + configs['portable'] + configs['custom'] + configs['command_line']
+ argv = configs['system'] + configs['user'] + configs['home'] + configs['portable'] + configs['custom'] + configs['command-line']
opts, args = parser.parse_args(argv)
if opts.verbose:
- for conf_label, conf in (
- ('System config', configs['system']),
- ('User config', configs['user']),
- ('Portable config', configs['portable']),
- ('Custom config', configs['custom']),
- ('Command-line args', configs['command_line'])):
- write_string('[debug] %s: %s\n' % (conf_label, repr(_hide_login_info(conf))))
+ for label in ('System', 'User', 'Portable', 'Home', 'Custom', 'Command-line'):
+ key = label.lower()
+ if paths.get(key) is None:
+ continue
+ if paths[key]:
+ write_string('[debug] %s config file: %s\n' % (label, paths[key]))
+ write_string('[debug] %s config: %s\n' % (label, repr(_hide_login_info(configs[key]))))
return parser, opts, args