tartube/tartube/options.py

2089 lines
78 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (C) 2019-2022 A S Lewis
#
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
"""Module that contains a class storing download options."""
# Import Gtk modules
# ...
# Import other modules
import os
import re
# Import our modules
import formats
import mainapp
import media
import utils
# Use same gettext translations
from mainapp import _
# Classes
class OptionsManager(object):
"""Partially based on the OptionsManager class in youtube-dl-gui.
This class handles settings for downloading media. Unlike youtube-dl-gui,
which has one group of download options applied to all downloads, this
object can be applied to any of the media data classes in media.py (so it
can be applied to a single video, or a whole channel, or generally to all
downloads).
Tartube's options.OptionsManager implements a subset of options implemented
by the equivalent class in youtube-dl-gui.
Options are listed here in the same order in which they appear in
youtube-dl's documentation.
OPTIONS
ignore_errors (bool): If True, youtube-dl will ignore the errors and
continue the download operation
abort_on_error (bool): If True, youtube-dl will abord downloading
further playlist videos if an error occurs
live_from_start (bool): If True, downloads livestreams from the start.
Currently only supported for YouTube (and marked experimental)
wait_for_video_min (int): Minimum number of seconds to wait between
retries for scheduled livestreams to become available (in seconds)
NETWORK OPTIONS
proxy (str): Use the specified HTTP/HTTPS proxy. If none is specified,
then Tartube will cycle through the list of proxies specified in
mainapp.TartubeApp.dl_proxy_list (if any)
socket_timeout (str): Time to wait before giving up, in seconds
source_address (str): Client-side IP address to bind to
force_ipv4 (str): Make all connections via IPv4
force_ipv6 (str): Make all connections via IPv6
GEO-RESTRICTION
geo_verification_proxy (str): Use this proxy to verify the IP address
for some geo-restricted sites
geo_bypass (bool): Bypass geographic restriction via faking
X-Forwarded-For HTTP header
no_geo_bypass (bool): Do not bypass geographic restriction via faking
X-Forwarded-For HTTP header
geo_bypass_country (str): Force bypass geographic restriction with
explicitly provided two-letter ISO 3166-2 country code
geo_bypass_ip_block (str): Force bypass geographic restriction with
explicitly provided IP block in CIDR notation
VIDEO SELECTION
playlist_start (int): Playlist index to start downloading
playlist_end (int): Playlist index to stop downloading
playlist_items (str): Comma-separated playlist index of the videos to
download, in the form '[START]:[STOP][:STEP]' or 'START-STOP'. Use
negative indices to count from the right and negative STEP to
download in reverse order, e.g. on a playhlist of 15 videos,
'1:3,7,-5::2' downloads the videos at index '1,2,3,7,11,13,15'
max_downloads (int): Maximum number of video files to download from the
given playlist
min_filesize (float): Minimum file size of the video file. If the video
file is smaller than the given size then youtube-dl will abort the
download operation
max_filesize (float): Maximum file size of the video file. If the video
file is larger than the given size then youtube-dl will abort the
download operation
date (str): Download only videos uploaded on this date (YYYYMMDD)
date_before (str): Download only videos uploaded on or before this date
(YYYYMMDD)
date_after (str): Download only videos uploaded on or after this date
(YYYYMMDD)
min_views (int): Do not download any videos with fewer than this many
views
max_views (int): Do not download any videos with more than this many
views
match_filter (str): Generic video filter (see the comments in the
youtube-dl documentation). Tartube automatically adds quotes to
the beginning and end of the string
age_limit (str): Download only videos suitable for the given age
include_ads (bool): Download advertisements (experimental)
DOWNLOAD OPTIONS
limit_rate (str): Bandwidth limit, in bytes (example strings: 50K or
4.2M) (not implemented by youtube-dl-gui)
NB: Can't be directly modified by user
retries (int): Number of youtube-dl retries
playlist_reverse (bool): When True, download playlist videos in reverse
order
playlist_random (bool): When True, download playlist videos in random
order
native_hls (bool): When True, youtube-dl will prefer the native HLS
(HTTP Live Streaming) implementation (rather than prefering FFmpeg,
which is at the current time the better downloader for general
compatibility)
hls_prefer_ffmpeg (bool): When True, youtube-dl will prefer FFmpeg
(N.B. This should not be confused with the 'prefer_ffmpeg' option)
external_downloader (str): Use the specified external downloaded.
youtube-dl currently supports the strings 'aria2c', 'avconv',
'axel', 'curl', 'ffmpeg', 'httpie', 'wget' (use an empty string to
disable this option)
external_arg_string (str): Arguments to pass to the external
downloader. Tartube automatically adds quotes to the beginning and
end of the string
FILESYSTEM OPTIONS
restrict_filenames (bool): If True, youtube-dl will restrict the
downloaded file's filename to ASCII characters only
nomtime (bool): When True will not use the last-modified header to set
the file modification time (i.e., use the time at which the server
believes the resources was last modified)
write_description (bool): If True, youtube-dl will write video
description to a .description file
write_info (bool): If True, youtube-dl will write video metadata to an
.info.json file
write_annotations (bool): If True, youtube-dl will write video
annotations to an .annotations.xml file
cookies_path (str): Path to the cookie jar. If not specified, then
Tartube will use the cookie jar 'cookies.txt' in the main
data directory
THUMBNAIL IMAGES
write_thumbnail (bool): If True youtube-dl will write thumbnail image
to disc
WORKAROUNDS
force_encoding (str): Force the specified encoding
no_check_certificate (bool): If True, suppress HTTPS certificate
validation
prefer_insecure (bool): If True, use an unencrypted connection to
retrieve information about the video. (Currently supported only for
YouTube)
user_agent (str): Specify a custom user agent for youtube-dl
referer (str): Specify a custom referer to use if the video access is
restricted to one domain
min_sleep_interval (int): Number of seconds to sleep before each
download when used alone, or a lower bound of a range for
randomised sleep before each download (minimum possible number of
seconds to sleep) when used along with 'max_sleep_interval'
max_sleep_interval (int): Upper bound of a range for randomized sleep
before each download (maximum possible number of seconds to sleep).
Can only be used along with a non-zero value for min_sleep_interval
VIDEO FORMAT OPTIONS
video_format (str): Video format to download. When this option is set
to '0' youtube-dl will choose the best video format available for
the given URL. Otherwise, set in a call to
OptionsParser.build_video_format(), combining the contents of the
'video_format_list' and 'video_format_mode' options. The combined
value is passed to youtube-dl with the -f switch
all_formats (bool): If True, download all available video formats.
Also set in the call to OptionsParser.build_video_format()
prefer_free_formats (bool): If True, prefer free video formats unless
one is specfied by video_format, etc
yt_skip_dash (bool): If True, do not download DASH-related data with
YouTube videos
merge_output_format (str): If a merge is required (e.g.
bestvideo+bestaudio), output to this container format. youtube-dl
supports the strings 'mkv', 'mp4', 'ogg', 'webm', 'flv' (or an
empty string to ignore this option)
SUBTITLE OPTIONS
write_subs (bool): If True, youtube-dl will try to download the
subtitles file for the given URL
write_auto_subs (bool): If True, youtube-dl will try to download the
automatic subtitles file for the given URL
write_all_subs (bool): If True, youtube-dl will try to download all the
the available subtitles files for the given URL
subs_format (str): Subtitle format preference. youtube-dl supports
'srt', 'ass', 'vtt', 'lrc' or combinations thereof, e.g.
'ass/srt/best'
subs_lang (str): Language of the subtitles file to download. Requires
the 'write_subs' option. Can not be set directly by the user;
instead, OptionsParser.parse() converts the option 'subs_lang_list'
to a string, and sets this option to that string
AUTHENTIFICATION OPTIONS
username (str): Username to login with
password (str): Password to login with
two_factor (str): Two-factor authentification code
net_rc (bool): If True, use .netrc authentification data
video_password (str): Video password for the given URL
ADOBE PASS OPTIONS
ap_mso (str): Adobe Pass multiple-system operator (TV provider)
identifier
ap_username (str): Multiple-system operator account login
ap_password (str): Multiple-system operator account password. If this
option is left out, yt-dlp will ask interactively
POST-PROCESSING OPTIONS
extract_audio (bool): If True, youtube-dl will post-process the video
file
audio_format (str): Audio format of the post-processed file. Available
values are 'mp3', 'wav', 'aac', 'm4a', 'vorbis', 'opus' & 'flac'
audio_quality (str): Audio quality of the post-processed file.
Available values are '9', '5', '0'. The lowest the value the better
the quality
recode_video (str): Encode the video to another format if necessary.
One of the strings 'avi', 'flv', 'mkv', 'mp4', 'ogg', 'webm', or an
empty string if disabled
pp_args (str): Give these arguments to the postprocessor. Tartube
automatically adds quotes to the beginning and end of the string
keep_video (bool): If True, youtube-dl will keep the video file after
post-processing it
embed_subs (bool): If True, youtube-dl will merge the subtitles file
with the video (only for .mp4 files)
embed_thumbnail (bool): When True will embed the thumbnail in the audio
file as cover art
add_metadata (bool): When True will write metadata to the video file
fixup_policy (str): Automatically correct known faults of the file.
The string can be 'never', 'warn', 'detect_or_worn' or an empty
string if disabled
prefer_avconv (bool): Prefer AVConv over FFmpeg for running the
postprocessors
prefer_ffmpeg (bool): Prefer FFmpeg over AVConv for running the
postprocessors
YT-DLP OPTIONS (will not work with other downloaders)
[not passed to yt-dlp directly]
output_format_list (list): List of arguments used with the '--output'
parameter, in the form TYPES:TEMPLATE. Each argument should have
a unique TYPES component. If this option is specified,
'output_format' and 'output_template' are ignored
output_path_list (list): List of arguments used with the '--paths'
paremeter, in the form TYPES:PATH. Each argument should have a
unique TYPES component. If 'output_path_list' contains any values,
then 'output_format_list' and/or 'output_format' are used without a
preceding absolute path
extractor_args_list (list): Pass these arguments to the extractor. You
can use this option multiple times to give different arguments to
different extractors. Each item in the list is in the form
KEY:ARGS
[Video Selection Options]
break_on_existing (bool): If True, stops the download process when
encountering a file that is in the archive
break_on_reject (bool): If True, stops the download process when
encountering a file that has been filtered out
skip_playlist_after_errors (int): Number of allowed failures until the
rest of the playlist is skipped
[Download Options]
concurrent_fragments (int): Number of fragments of a DASH/hlsnative
video that should be download concurrently (default is 1)
throttled_rate (int): Minimum download rate in bytes per second below
which throttling is assumed and the video data is re-extracted
(e.g. 100K)
[Filesystem Options]
windows_filenames (bool): If True, forces filenames to be MS Windows
compatible
trim_filenames (int): Limit the filename length (excluding extension)
to the specified number of characters
no_overwrites (bool): If True, does not overwrite any files
force_overwrites (bool): If True, overwrites all video and metadata
files. This option includes '--no-continue' (for which there is no
Tartube download option)
write_playlist_metafiles (bool): If True, writes playlist metadata in
addition to the video metadata when using --write-info-json,
--write-description etc. (default)
no_clean_info_json (bool): If True, writes all fields to the infojson
(default is to remove some private fields)
no_cookies (bool): If True, does not read/dump cookies from/to file
(default)
cookies_from_browser (str): The name of the browser and (optionally)
the name/path of the profile to load cookies from; a string in the
from BROWSER[+KEYRING][:PROFILE]
no_cookies_from_browser (bool): If true, does not load cookies from the
browser (default)
[Internet Shortcut Options]
write_link (bool): If True, writes an internet shortcut file, depending
on the current platform (.url, .webloc or .desktop). The URL may be
cached by the OS
write_url_link (bool): If True, writes a .url Windows internet
shortcut. The OS caches the URL based on the file path
write_webloc_link (bool): If True, writes a .webloc macOS internet
shortcut
write_desktop_link (bool): If True, writes a .desktop Linux internet
shortcut
[Verbosity and Simulation Options]
ignore_no_formats_error (bool): If True, ignore "No video formats"
error. Useful for extracting metadata even if the video is not
actually available for download (experimental)
force_write_archive (bool): If True, forces download archive entries to
be written as far as no errors occur, even if -s or another
simulation option is used
[Workaround Options]
sleep_requests (int): Number of seconds to sleep between requests
during data extraction
sleep_subtitles (int): Number of seconds to sleep before each download.
This is the minimum time to sleep when used along with
'max_sleep_interval'
[Video Format Options]
video_multistreams (bool): If True, allows multiple video streams to be
merged into a single file
audio_multistreams (bool): If True, allows multiple audio streams to be
merged into a single file
check_formats (bool): If True, checks that the formats selected are
actually downloadable (Experimental)
allow_unplayable_formats (bool): If True, allows unplayable formats to
be listed and downloaded. All video post-processing will also be
turned off
[Post-Processing Options]
remux_video (str): Remux the video into another container if necessary
(currently supported: mp4|mkv|flv|webm|mov|avi|mp3|mka|m4a|ogg
|opus). 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.
embed_metadata (bool): Embed metadata including chapter markers (if
supported by the format) to the video file
convert_thumbnails (str): Convert the thumbnails to another format
(currently supported: jpg|png)
split_chapters (bool): Split video into multiple files based on
internal chapters. The "chapter:" prefix can be used with
'output_path_list' and 'output_template_list' to set the output
filename for the split files
[Extractor Options]
extractor_retries (str): Number of retries for known extractor errors
(default is '3'), or 'infinite'
no_allow_dynamic_mpd (bool): If True, do not process dynamic DASH
manifests
hls_split_discontinuity (bool): If True, splits HLS playlists to
different formats at discontinuities such as ad breaks
YOUTUBE-DL-GUI OPTIONS (not passed to youtube-dl directly)
[used to build parameters of --output and --paths]
output_format (int): Option in the range 0-9, which is converted into
a youtube-dl output template using
formats.FILE_OUTPUT_CONVERT_DICT. If the value is 0, then the
custom 'output_template' is used instead
output_template (str): Can be any output template supported by
youtube-dl. Ignored if 'output_format' is not 0
[used in conjunction with the 'min_filesize' & 'max_filesize' options]
max_filesize_unit (str): Maximum file size unit. Available values:
'' (for bytes), 'k' (for kilobytes, etc), 'm', 'g', 't', 'p',
'e', 'z', 'y'
min_filesize_unit (str): Minimum file size unit. Available values
as above
[in youtube-dl-gui, this was named 'cmd_args']
extra_cmd_string (str): String that contains extra youtube-dl options
separated by spaces. Components containing whitespace can be
enclosed within double quotes "..."
direct_cmd_flag (str): If True, only those command options specified by
extra_cmd_string (including the source URL) are used; Tartube
merely adds the downloader (e.g. 'youtube-dl') and the output
directory switch (i.e. -o)
direct_url_flag (str): If True, Tartube assumes that
'extra_cmd_string' contains the URL to check/download. Otherwise,
the source URL of each affected media data object(s) is used, as
normal. Ignored if 'direct_cmd_flag' is False
TARTUBE OPTIONS (not passed to youtube-dl directly)
move_description (bool):
move_info (bool):
move_annotations (bool):
move_thumbnail (bool):
During a download operation (real or simulated), if these values
are True, the video description/JSON/annotations files are moved to
a '.data' sub-directory, and the thumbnails are moved to a
'.thumbs' sub-directory, inside the directory containing the videos
keep_description (bool):
keep_info (bool):
keep_annotations (bool):
keep_thumbnail (bool):
During a download operation (not simulated, e.g. when the user
clicks the 'Download all' button), the video description/JSON/
annotations/thumbnail files are downloaded only if
'write_description', 'write_info', 'write_annotations' and/or
'write_thumbnail' are True
They are initially stored in the same sub-directory in which
Tartube will store the video
If these options are True, they stay there; otherwise, they are
copied into the equivalent location in Tartube's temporary
directories.
sim_keep_description (bool):
sim_keep_info (bool):
sim_keep_annotations (bool):
sim_keep_thumbnail (bool):
During a download operation (simulated, e.g. when the user clicks
the 'Check all' button), the video's JSON file is always loaded
into memory
If 'write_description' and 'sim_keep_description' are both true,
the description file is written directly to the sub-directory in
which Tartube would store the video
If 'write_description' is true but 'sim_keep_description' not, the
description file is written to the equivalent location in Tartube's
temporary directories.
The same applies to the JSON, annotations and thumbnail files.
use_fixed_folder (str or None): If not None, then all videos are
downloaded to one of Tartube's fixed folders (not including private
folders) - currently, that group consists of only 'Temporary
Videos' and 'Unsorted Videos'. The value should match the name of
the folder
match_title_list (list): Download only matching titles (regex or
caseless sub-string). Each item in the list is passed to youtube-dl
as a separate --match-title argument
reject_title_list (list): Skip download for any matching titles (regex
or caseless sub-string). Each item in the list is passed to
youtube-dl as a separate --reject-title argument
video_format_list (list): List of video formats to download, in order
of preference. If an empty list, youtube-dl will choose the best
video format available for the given URL. Otherwise, the items in
this list are keys in formats.VIDEO_FORMAT_DICT. The corresponding
values are combined and stored as the 'video_format' option, first
being rearrnaged to put video formats before audio formats
(otherwise youtube-dl won't download the video formats)
video_format_mode (str): 'all' to download all available formats,
ignoring the preference list (sets the option 'all_formats').
'single' to download the first available format in
'video_format_list'. 'single_agree' to download the first format in
'video_format_list' that's available for all videos. 'multiple' to
download all available formats in 'video_format_list'
subs_lang_list (list): List of language tags which are used to set
the 'subs_lang' option
downloader_config (bool): If true, a youtube-dl configuration is
specified with the '--config-location' option. On Linux/MacOS, the
user-wide configuration file is used
('~/.config/youtube-dl/config'). On MS Windows, a file in the
Tartube directory is used (youtube-dl.conf)
"""
# Standard class methods
def __init__(self, uid, name, dbid=None):
# IV list - other
# ---------------
# Unique ID for this options manager
self.uid = uid
# A non-unique name for this options manager. Managers that are
# attached to a media data object have the same name as that object
# (The name is not unique because, for example, videos could have the
# same name as a channel; it's up to the user to avoid duplicate
# names)
# Empty strings are not valid as names
self.name = name
# A short description, intended for use in the Drag and Drop tab
# Empty strings are valid as descriptions
self.descrip = name
# If this object is attached to a media data object, the .dbid of that
# object; otherwise None
self.dbid = dbid
# Dictionary of download options for youtube-dl, set by a call to
# self.reset_options
self.options_dict = {}
# Code
# ----
# Initialise youtube-dl options
self.reset_options()
# Public class methods
def clone_options(self, other_options_manager_obj):
"""Called by mainapp.TartubeApp.apply_download_options(),
.clone_download_options() and .clone_download_options_from_window().
Clones download options from the specified object into this object,
completely replacing this object's download options.
Args:
other_options_manager_obj (options.OptionsManager): The download
options object (usually the General Options Manager), from
which options will be cloned
"""
self.options_dict = other_options_manager_obj.options_dict.copy()
# In the dictionary's key-value pairs, some values are themselves lists
# that must be copied directly
for key in [
'match_title_list', 'reject_title_list', 'video_format_list',
'subs_lang_list',
]:
self.options_dict[key] \
= other_options_manager_obj.options_dict[key].copy()
def rearrange_formats(self):
"""Called by config.OptionsEditWin.apply_changes().
The option 'video_format_list' specifies video formats, audio formats
or a mixture of both.
youtube-dl won't download the specified formats properly, if audio
formats appear before video formats. Therefore, this function is called
to rearrange the list, putting all video formats above all audio
formats.
"""
format_list = self.options_dict['video_format_list']
video_list = []
audio_list = []
comb_list = []
for code in format_list:
if code != '0':
if formats.VIDEO_OPTION_TYPE_DICT[code] is False:
video_list.append(code)
else:
audio_list.append(code)
comb_list.extend(video_list)
comb_list.extend(audio_list)
self.options_dict['video_format_list'] = format_list
def reset_options(self):
"""Called by self.__init__().
Resets (or initialises) self.options_dict to its default state.
"""
if os.name == 'nt':
windows_filenames_flag = True
else:
windows_filenames_flag = False
self.options_dict = {
# OPTIONS
'ignore_errors': True,
'abort_on_error': False,
'live_from_start': False,
'wait_for_video_min': 0,
# NETWORK OPTIONS
'proxy': '',
'socket_timeout': '',
'source_address': '',
'force_ipv4': False,
'force_ipv6': False,
# GEO-RESTRICTION
'geo_verification_proxy': '',
'geo_bypass': False,
'no_geo_bypass': False,
'geo_bypass_country': '',
'geo_bypass_ip_block': '',
# VIDEO SELECTION
'playlist_start': 1,
'playlist_end': 0,
'playlist_items': '',
'max_downloads': 0,
'min_filesize': 0,
'max_filesize': 0,
'date': '',
'date_before': '',
'date_after': '',
'min_views': 0,
'max_views': 0,
'match_filter': '',
'age_limit': '',
'include_ads': False,
# DOWNLOAD OPTIONS
'limit_rate': '', # Can't be directly modified by user
'retries': 10,
'playlist_reverse': False,
'playlist_random': False,
'native_hls': True,
'hls_prefer_ffmpeg': False,
'external_downloader': '',
'external_arg_string': '',
# FILESYSTEM OPTIONS
'restrict_filenames': False,
'nomtime': False,
'write_description': True,
'write_info': True,
'write_annotations': False,
'cookies_path': '',
# THUMBNAIL IMAGES
'write_thumbnail': True,
# VERBOSITY / SIMULATION OPTIONS
# (none implemented)
# WORKAROUNDS
'force_encoding': '',
'no_check_certificate': False,
'prefer_insecure': False,
'user_agent': '',
'referer': '',
'min_sleep_interval': 0,
'max_sleep_interval': 0,
# VIDEO FORMAT OPTIONS
'video_format': '0',
'all_formats': False,
'prefer_free_formats': False,
'yt_skip_dash': False,
'merge_output_format': '',
# SUBTITLE OPTIONS
'write_subs': False,
'write_auto_subs': False,
'write_all_subs': False,
'subs_format': '',
'subs_lang': '',
# AUTHENTIFICATION OPTIONS
'username': '',
'password': '',
'two_factor': '',
'net_rc': False,
'video_password': '',
# ADOBE PASS OPTIONS
'ap_mso': '',
'ap_username': '',
'ap_password': '',
# POST-PROCESSING OPTIONS
'extract_audio': False,
'audio_format': '',
'audio_quality': '5',
'recode_video': '',
'pp_args': '',
'keep_video': False,
'embed_subs': False,
'embed_thumbnail': False,
'add_metadata': False,
'fixup_policy': '',
'prefer_avconv': False,
'prefer_ffmpeg': False,
# YT-DLP OPTIONS
# (not passed to yt-dlp directly)
'output_format_list': [],
'output_path_list': [],
'extractor_args_list': [],
# (Video Selection Options)
'break_on_existing': False,
'break_on_reject': False,
'skip_playlist_after_errors': 0,
# (Download Options)
'concurrent_fragments': 1,
'throttled_rate': 0,
# (Filesystem Options)
'windows_filenames': windows_filenames_flag,
'trim_filenames': 0,
'no_overwrites': False,
'force_overwrites': False,
'write_playlist_metafiles': False,
'no_clean_info_json': False,
'no_cookies': False,
'cookies_from_browser': '',
'no_cookies_from_browser': True,
# (Internet Shortcut Options)
'write_link': False,
'write_url_link': False,
'write_webloc_link': False,
'write_desktop_link': False,
# (Verbosity and Simulation Options)
'ignore_no_formats_error': False,
'force_write_archive': False,
# (Workaround Options)
'sleep_requests': 0,
'sleep_subtitles': 0,
# (Video Format Options)
'video_multistreams': False,
'audio_multistreams': False,
'check_formats': False,
'allow_unplayable_formats': False,
# (Post-Processing Options)
'remux_video': '',
'embed_metadata': False,
'convert_thumbnails': '',
'split_chapters': False,
# (Extractor Options)
'extractor_retries': '3',
'no_allow_dynamic_mpd': False,
'hls_split_discontinuity': False,
# YOUTUBE-DL-GUI OPTIONS
'output_format': 2,
'output_template': '%(title)s.%(ext)s',
'max_filesize_unit': '',
'min_filesize_unit': '',
'extra_cmd_string': '',
'direct_cmd_flag': False,
'direct_url_flag': False,
# TARTUBE OPTIONS
'move_description': False,
'move_info': False,
'move_annotations': False,
'move_thumbnail': False,
'keep_description': False,
'keep_info': False,
'keep_annotations': False,
'keep_thumbnail': True,
'sim_keep_description': False,
'sim_keep_info': False,
'sim_keep_annotations': False,
'sim_keep_thumbnail': True,
'use_fixed_folder': None,
'match_title_list': [],
'reject_title_list': [],
'video_format_list': [],
'video_format_mode': 'single',
'subs_lang_list': [ 'en' ],
'downloader_config': False,
}
def set_general_options(self):
"""Called by mainapp.TartubeApp.start().
Configures this object with a suitable description.
"""
self.descrip = _('General (default) download options')
def set_classic_mode_options(self, no_descrip_flag=False):
"""Called by mainapp.TartubeApp.start() and
.apply_classic_download_options().
Also called by self.set_mp3_options().
Configures this object for use in the Classic Mode tab.
Args:
no_descrip_flag (bool): Set to True when called from
self.set_mp3_options()
"""
if not no_descrip_flag:
self.descrip = _('Download options for the Classic Mode tab')
self.options_dict['write_description'] = False
self.options_dict['write_info'] = False
self.options_dict['write_annotations'] = False
self.options_dict['write_thumbnail'] = False
self.options_dict['move_description'] = False
self.options_dict['move_info'] = False
self.options_dict['move_annotations'] = False
self.options_dict['move_thumbnail'] = False
self.options_dict['keep_description'] = False
self.options_dict['keep_info'] = False
self.options_dict['keep_annotations'] = False
self.options_dict['keep_thumbnail'] = False
self.options_dict['sim_keep_description'] = False
self.options_dict['sim_keep_info'] = False
self.options_dict['sim_keep_annotations'] = False
self.options_dict['sim_keep_thumbnail'] = False
def set_mp3_options(self):
"""Called by mainapp.TartubeApp.start().
Configures this object to download MP3s.
"""
self.descrip = _('Download and convert to MP3 (requires FFmpeg)')
# (Actual downloads take place in the Classic Mode tab, so use the same
# file options)
self.set_classic_mode_options(True)
# (Convert everything to MP3)
self.options_dict['extract_audio'] = True
self.options_dict['audio_format'] = 'mp3'
# Set accessors
def set_dbid(self, dbid):
self.dbid = dbid
def reset_dbid(self):
self.dbid = None
class OptionsParser(object):
"""Called by downloads.DownloadManager.__init__() and by
mainwin.SystemCmdDialogue.update_textbuffer().
This object converts the download options specified by an
options.OptionsManager object into a list of youtube-dl command line
options, whenever required.
Args:
app_obj (mainapp.TartubeApp): The main application
"""
# Standard class methods
def __init__(self, app_obj):
# IV list - class objects
# -----------------------
# The main application
self.app_obj = app_obj
# IV list - other
# ---------------
# List of options.OptionHolder objects, with their initial settings
# The options here are in the same order in which they appear in
# youtube-dl's options list
self.option_holder_list = [
# OPTIONS
# -i, --ignore-errors
OptionHolder('ignore_errors', '-i', False),
# --abort-on-error
OptionHolder('abort_on_error', '--abort-on-error', False),
# --live-from-start
OptionHolder('live_from_start', '--live-from-start', False),
# --wait-for-video MIN (N.B. the MAX value is not supported)
OptionHolder('wait_for_video_min', '--wait-for-video', 0),
# NETWORK OPTIONS
# --proxy URL
OptionHolder('proxy', '--proxy', ''),
# --socket-timeout SECONDS
OptionHolder('socket_timeout', '--socket-timeout', ''),
# --source-address IP
OptionHolder('source_address', '--source-address', ''),
# -4, --force-ipv4
OptionHolder('force_ipv4', '--force-ipv4', False),
# -6, --force-ipv6
OptionHolder('force_ipv6', '--force-ipv6', False),
# GEO-RESTRICTION
# --geo-verification-proxy URL
OptionHolder(
'geo_verification_proxy',
'--geo-verification-proxy',
'',
),
# --geo-bypass
OptionHolder('geo_bypass', '--geo-bypass', False),
# --no-geo-bypass
OptionHolder('no_geo_bypass', '--no-geo-bypass', False),
# --geo-bypass-country CODE
OptionHolder('geo_bypass_country', '--geo-bypass-country', ''),
# --geo-bypass-ip-block IP_BLOCK
OptionHolder('geo_bypass_ip_block', '--geo-bypass-ip-block', ''),
# VIDEO SELECTION
# --playlist-start NUMBER
OptionHolder('playlist_start', '--playlist-start', 1),
# --playlist-end NUMBER
OptionHolder('playlist_end', '--playlist-end', 0),
# --playlist-items ITEM_SPEC
OptionHolder('playlist_items', '--playlist-items', ''),
# --max-downloads NUMBER
OptionHolder('max_downloads', '--max-downloads', 0),
# --min-filesize SIZE
OptionHolder('min_filesize', '--min-filesize', 0),
# --max-filesize SIZE
OptionHolder('max_filesize', '--max-filesize', 0),
# --date DATE
OptionHolder('date', '--date', ''),
# --datebefore DATE
OptionHolder('date_before', '--datebefore', ''),
# --dateafter DATE
OptionHolder('date_after', '--dateafter', ''),
# --min-views COUNT
OptionHolder('min_views', '--min-views', 0),
# --max-views COUNT
OptionHolder('max_views', '--max-views', 0),
# --match-filter FILTER
OptionHolder('match_filter', '--match-filter', ''),
# --age-limit YEARS
OptionHolder('age_limit', '--age-limit', ''),
# --include-ads
OptionHolder('include_ads', '--include-ads', False),
# DOWNLOAD OPTIONS
# -r, --limit-rate RATE
OptionHolder('limit_rate', '-r', ''),
# -R, --retries RETRIES
OptionHolder('retries', '-R', 10),
# --playlist-reverse
OptionHolder('playlist_reverse', '--playlist-reverse', False),
# --playlist-random
OptionHolder('playlist_random', '--playlist-random', False),
# --hls-prefer-native
OptionHolder('native_hls', '--hls-prefer-native', False),
# --hls-prefer-ffmpeg
OptionHolder('hls_prefer_ffmpeg', '--hls-prefer-ffmpeg', False),
# --external-downloader COMMAND
OptionHolder('external_downloader', '--external-downloader', ''),
# --external-downloader-args ARGS
OptionHolder(
'external_arg_string',
'--external-downloader-args',
'',
),
# FILESYSTEM OPTIONS
# --restrict-filenames
OptionHolder('restrict_filenames', '--restrict-filenames', False),
# --no-mtime
OptionHolder('nomtime', '--no-mtime', False),
# --write-description
OptionHolder('write_description', '--write-description', False),
# --write-info-json
OptionHolder('write_info', '--write-info-json', False),
# --write-annotations
OptionHolder('write_annotations', '--write-annotations', False),
# --cookies FILE
OptionHolder('cookies_path', '--cookies', ''),
# THUMBNAIL IMAGES
# --write-thumbnail
OptionHolder('write_thumbnail', '--write-thumbnail', False),
# VERBOSITY / SIMULATION OPTIONS
# (none implemented)
# WORKAROUNDS
# --encoding ENCODING
OptionHolder('force_encoding', '--encoding', ''),
# --no-check-certificate
OptionHolder(
'no_check_certificate',
'--no-check-certificate',
False,
),
# --prefer-insecure
OptionHolder('prefer_insecure', '--prefer-insecure', False),
# --user-agent UA
OptionHolder('user_agent', '--user-agent', ''),
# --referer URL
OptionHolder('referer', '--referer', ''),
# --sleep-interval SECONDS
OptionHolder('min_sleep_interval', '--sleep-interval', 0),
# --max-sleep-interval SECONDS
OptionHolder('max_sleep_interval', '--max-sleep-interval', 0),
# VIDEO FORMAT OPTIONS
# -f, --format FORMAT
OptionHolder('video_format', '-f', '0'),
# --all-formats
OptionHolder('all_formats', '--all-formats', False),
# --prefer-free-formats
OptionHolder(
'prefer_free_formats',
'--prefer-free-formats',
False,
),
# --youtube-skip-dash-manifest
OptionHolder(
'yt_skip_dash',
'--youtube-skip-dash-manifest',
False,
),
# --merge-output-format FORMAT
OptionHolder('merge_output_format', '--merge-output-format', ''),
# SUBTITLE OPTIONS
# --write-sub
OptionHolder('write_subs', '--write-sub', False),
# --write-auto-sub
OptionHolder('write_auto_subs', '--write-auto-sub', False),
# --all-subs
OptionHolder('write_all_subs', '--all-subs', False),
# --sub-format FORMAT
OptionHolder('subs_format', '--sub-format', ''),
# --sub-lang LANGS
# NB This '--sub-lang' string is not the one used as a switch by
# self.parse()
OptionHolder('subs_lang', '--sub-lang', '', ['write_subs']),
# AUTHENTIFICATION OPTIONS
# -u, --username USERNAME
OptionHolder('username', '-u', ''),
# -p, --password PASSWORD
OptionHolder('password', '-p', ''),
# -2, --twofactor TWOFACTOR
OptionHolder('two_factor', '--twofactor', ''),
# -n, --netrc
OptionHolder('net_rc', '--netrc', False),
# --video-password PASSWORD
OptionHolder('video_password', '--video-password', ''),
# ADOBE PASS OPTIONS
# --ap-mso MSO
OptionHolder('ap_mso', '--ap-mso', ''),
# --ap-username USERNAME
OptionHolder('ap_username', '--ap-username', ''),
# --ap-password PASSWORD
OptionHolder('ap_password', '--ap-password', ''),
# POST-PROCESSING OPTIONS
# -x, --extract-audio
OptionHolder('extract_audio', '-x', False),
# --audio-format FORMAT
OptionHolder('audio_format', '--audio-format', ''),
# --audio-quality QUALITY
OptionHolder(
'audio_quality',
'--audio-quality',
'5',
['extract_audio'],
),
# --recode-video FORMAT
OptionHolder('recode_video', '--recode-video', ''),
# --postprocessor-args ARGS
OptionHolder('pp_args', '--postprocessor-args', ''),
# -k, --keep-video
OptionHolder('keep_video', '-k', False),
# --embed-subs
OptionHolder(
'embed_subs',
'--embed-subs',
False,
['write_auto_subs', 'write_subs'],
),
# --embed-thumbnail
OptionHolder('embed_thumbnail', '--embed-thumbnail', False),
# --add-metadata
OptionHolder('add_metadata', '--add-metadata', False),
# --fixup POLICY
OptionHolder('fixup_policy', '--fixup', ''),
# --prefer-avconv
OptionHolder('prefer_avconv', '--prefer-avconv', False),
# --prefer-ffmpeg
OptionHolder('prefer_ffmpeg', '--prefer-ffmpeg', False),
# YT-DLP OPTIONS
# (not given an options.OptionHolder object)
# OptionHolder('output_format_list', '', []),
# OptionHolder('output_path_list', '', []),
# (Video Selection Options)
# --break-on-existing
OptionHolder('break_on_existing', '--break-on-existing', False),
# --break-on-reject
OptionHolder('break_on_reject', '--break-on-reject', False),
# --skip-playlist-after-errors N
OptionHolder(
'skip_playlist_after_errors',
'--skip-playlist-after-errors',
0,
),
# (Download Options)
# --concurrent-fragments N
OptionHolder('concurrent_fragments', '--concurrent-fragments', 1),
# --throttled-rate RATE
OptionHolder('throttled_rate', '--throttled-rate', 0),
# (Filesystem Options)
# --windows-filenames
OptionHolder('windows_filenames', '--windows-filenames', False),
# --trim-filenames LENGTH
OptionHolder('trim_filenames', '--trim-filenames', 0),
# --no-overwrites
OptionHolder('no_overwrites', '--no-overwrites', False),
# --force-overwrites
OptionHolder('force_overwrites', '--force-overwrites', False),
# --write-playlist-metafiles
OptionHolder(
'write_playlist_metafiles',
'--write-playlist-metafiles',
False,
),
# --no-clean-infojson
OptionHolder('no_clean_info_json', '--no-clean-infojson', False),
# --no-cookies
OptionHolder('no_cookies', '--no-cookies', False),
# --cookies-from-browser BROWSER[+KEYRING][:PROFILE]
OptionHolder('cookies_from_browser', '--cookies-from-browser', ''),
# --no-cookies-from-browser
OptionHolder(
'no_cookies_from_browser',
'--no-cookies-from-browser',
True,
),
# (Internet Shortcut Options)
# --write-link
OptionHolder('write_link', '--write-link', False),
# --write-url-link
OptionHolder('write_url_link', '--write-url-link', False),
# --write-webloc-link
OptionHolder('write_webloc_link', '--write-webloc-link', False),
# --write-desktop-link
OptionHolder('write_desktop_link', '--write-desktop-link', False),
# (Verbosity and Simulation Options)
# --ignore-no-formats-error
OptionHolder(
'ignore_no_formats_error',
'--ignore-no-formats-error',
False,
),
# --force-write-archive
OptionHolder(
'force_write_archive',
'--force-write-archive',
False,
),
# (Workaround Options)
# --sleep-requests SECONDS
OptionHolder('sleep_requests', '--sleep-requests', 0),
# --sleep-subtitles SECONDS
OptionHolder('sleep_subtitles', '--sleep-subtitles', 0),
# (Video Format Options)
# --video-multistreams
OptionHolder('video_multistreams', '--video-multistreams', False),
# --audio-multistreams
OptionHolder('audio_multistreams', '--audio-multistreams', False),
# --check-formats
OptionHolder('check_formats', '--check-formats', False),
# --allow-unplayable-formats
OptionHolder(
'allow_unplayable_formats',
'--allow-unplayable-formats',
False,
),
# (Post-Processing Options)
# --remux-video FORMAT
OptionHolder('remux_video', '--remux-video', ''),
# --embed-metadata
OptionHolder('embed_metadata', '--embed-metadata', False),
# --convert-thumbnails FORMAT
OptionHolder('convert_thumbnails', '--convert-thumbnails', ''),
# --split-chapters
OptionHolder('split_chapters', '--split-chapters', False),
# (Extractor Options)
# --extractor-retries RETRIES
OptionHolder('extractor_retries', '--extractor-retries', '3'),
# --no-allow-dynamic-mpd
OptionHolder(
'no_allow_dynamic_mpd',
'--no-allow-dynamic-mpd',
False,
),
# --hls-split-discontinuity
OptionHolder(
'hls_split_discontinuity',
'--hls-split-discontinuity',
False,
),
# YOUTUBE-DL-GUI OPTIONS (not given an options.OptionHolder object)
# OptionHolder('output_format', '', 2),
# OptionHolder('output_template', '', ''),
# OptionHolder('max_filesize_unit', '', ''),
# OptionHolder('min_filesize_unit', '', ''),
# OptionHolder('extra_cmd_string', '', ''),
# OptionHolder('direct_cmd_flag', '', False),
# OptionHolder('direct_url_flag', '', False),
# TARTUBE OPTIONS (not given an options.OptionHolder object)
# OptionHolder('move_description', '', False),
# OptionHolder('move_info', '', False),
# OptionHolder('move_annotations', '', False),
# OptionHolder('move_thumbnail', '', False),
# OptionHolder('keep_description', '', False),
# OptionHolder('keep_info', '', False),
# OptionHolder('keep_annotations', '', False),
# OptionHolder('keep_thumbnail', '', False),
# OptionHolder('sim_keep_description', '', False),
# OptionHolder('sim_keep_info', '', False),
# OptionHolder('sim_keep_annotations', '', False),
# OptionHolder('sim_keep_thumbnail', '', False),
# OptionHolder('use_fixed_folder', '', None),
# OptionHolder('match_title_list', '', []),
# OptionHolder('reject_title_list', '', []),
# OptionHolder('video_format_list', '', []),
# OptionHolder('video_format_mode', '', 'single'),
# OptionHolder('subs_lang_list', '', []),
# OptionHolder('downloader_config', '', False),
]
# Public class methods
def parse(self, media_data_obj, options_manager_obj,
operation_type='real', scheduled_obj=None):
"""Called by downloads.DownloadWorker.prepare_download() and
mainwin.MainWin.update_textbuffer() and several other functions.
Converts the download options stored in the specified
options.OptionsManager object into a list of youtube-dl command line
options.
Args:
media_data_obj (media.Video, media.Channel, media.Playlist,
media.Folder): The media data object being downloaded
options_manager_obj (options.OptionsManager): The object containing
the download options for this media data object
operation_type (str): 'sim', 'real', 'custom_sim', 'custom_real',
'classic_sim', 'classic_real', 'classic_custom' (matching
possible values of downloads.DownloadManager.operation_type)
scheduled_obj (media.Scheduled): If a scheduled download is
involved, the corresponding object (so bandwidth limits can be
extracted)
Returns:
List of strings with all the youtube-dl command line options
"""
# Force youtube-dl's progress bar to be outputted as separate lines
options_list = ['--newline']
# Create a copy of the dictionary
copy_dict = options_manager_obj.options_dict.copy()
# Get the directory into which files are downloaded
dir_path = self.build_dir(
media_data_obj,
copy_dict,
operation_type,
)
# Modify various values in the copy. Set the 'video_format' and
# 'all_formats' options
self.build_video_format(media_data_obj, copy_dict, operation_type)
# Set the 'min_filesize' and 'max_filesize' options
self.build_file_sizes(copy_dict)
# Set the 'limit_rate' option
self.build_limit_rate(copy_dict, scheduled_obj)
# Set the 'proxy' option
self.build_proxy(copy_dict)
# Parse basic youtube-dl command line options
for option_holder_obj in self.option_holder_list:
# First deal with special cases...
if option_holder_obj.name == 'extract_audio':
if copy_dict['audio_format'] == '':
value = copy_dict[option_holder_obj.name]
if value != option_holder_obj.default_value:
options_list.append(option_holder_obj.switch)
elif option_holder_obj.name == 'audio_format':
value = copy_dict[option_holder_obj.name]
if copy_dict['extract_audio'] \
and value != option_holder_obj.default_value:
options_list.append('-x')
options_list.append(option_holder_obj.switch)
options_list.append(utils.to_string(value))
# The '-x' / '--audio-quality' switch must precede the
# '--audio-quality' switch, if both are used
# Therefore, if the current value of the 'audio_quality'
# option is not the default value ('5'), then insert the
# '--audio-quality' switch into the options list right
# now
if copy_dict['audio_quality'] != '5':
options_list.append('--audio-quality')
options_list.append(
utils.to_string(copy_dict['audio_quality']),
)
elif option_holder_obj.name == 'audio_quality':
# If the '--audio-quality' switch was not added by the code
# block just above, then follow the standard procedure
if option_holder_obj.switch not in options_list:
if option_holder_obj.check_requirements(copy_dict):
value = copy_dict[option_holder_obj.name]
if value != option_holder_obj.default_value:
options_list.append(option_holder_obj.switch)
options_list.append(utils.to_string(value))
elif option_holder_obj.name == 'match_filter':
value = utils.to_string(copy_dict[option_holder_obj.name])
if self.app_obj.block_livestreams_flag:
if value == '':
value = '!is_live'
else:
value += ' \& !is_live'
if value != '':
options_list.append(option_holder_obj.switch)
options_list.append(value)
elif option_holder_obj.name == 'external_arg_string' \
or option_holder_obj.name == 'pp_args':
value = copy_dict[option_holder_obj.name]
if value != '':
options_list.append(option_holder_obj.switch)
options_list.append('"' + utils.to_string(value) + '"')
elif option_holder_obj.name == 'cookies_path':
cookies_path = copy_dict[option_holder_obj.name]
options_list.append('--cookies')
# If no path is specified, use a standard location for the
# cookie jar (otherwise youtube-dl(c) will write it to
# ../tartube/tartube)
if cookies_path == '':
options_list.append(
os.path.abspath(
os.path.join(
self.app_obj.data_dir,
self.app_obj.cookie_file_name,
),
),
)
else:
options_list.append(cookies_path)
elif option_holder_obj.name == 'trim_filenames':
length = copy_dict[option_holder_obj.name]
# The --trim-filenames option specifies a length that includes
# the directory name. If the user has specified a length that
# is shorter than the directory name, then ignore this
# option
if length >= (len(dir_path) + 2):
options_list.append('--trim-filenames')
options_list.append(str(length))
# For all other options, just check the value is valid
elif option_holder_obj.check_requirements(copy_dict):
value = copy_dict[option_holder_obj.name]
if value != option_holder_obj.default_value:
options_list.append(option_holder_obj.switch)
if not option_holder_obj.is_boolean():
options_list.append(utils.to_string(value))
# Parse the 'match_title_list' and 'reject_title_list'
for item in copy_dict['match_title_list']:
options_list.append('--match-title')
options_list.append(item)
for item in copy_dict['reject_title_list']:
options_list.append('--reject-title')
options_list.append(item)
# Parse the 'subs_lang_list' option
if copy_dict['write_subs'] \
and not copy_dict['write_auto_subs'] \
and not copy_dict['write_all_subs'] \
and copy_dict['subs_lang_list']:
options_list.append('--sub-lang')
options_list.append(','.join(copy_dict['subs_lang_list']))
# Parse the 'extractor_args_list' option
for item in copy_dict['extractor_args_list']:
options_list.append('--extractor-args')
options_list.append(item)
# Build the --output and --paths options
options_list = self.build_paths(
dir_path,
copy_dict,
options_list,
)
# Parse the 'extra_cmd_string' option, so it overrules everything else.
# The option can contain arguments inside double quotes "..."
# (arguments that can therefore contain whitespace)
parsed_list = utils.parse_options(copy_dict['extra_cmd_string'])
for item in parsed_list:
options_list.append(item)
# Parse the 'downloader_config' option, so it overrules everything
# else
if copy_dict['downloader_config']:
options_list.append('--config-location')
options_list.append(utils.get_dl_config_path(self.app_obj))
# Filter out yt-dlp options, if required. A list of them is specified
# in mainapp.TartubeApp.ytdlp_exclusive_options_dict
if self.app_obj.ytdlp_filter_options_flag \
and (
self.app_obj.ytdl_fork is None \
or self.app_obj.ytdl_fork != 'yt-dlp'
):
filter_list = options_list.copy()
options_list = []
while filter_list:
item = filter_list.pop(0)
if item in self.app_obj.ytdlp_exclusive_options_dict:
if self.app_obj.ytdlp_exclusive_options_dict[item]:
# This option takes an argument
filter_list.pop(0)
else:
options_list.append(item)
# Parsing complete
return options_list
def build_file_sizes(self, copy_dict):
"""Called by self.parse().
Build the value of the 'min_filesize' and 'max_filesize' options and
store them in the options dictionary.
Args:
copy_dict (dict): Copy of the original options dictionary.
"""
if copy_dict['min_filesize']:
copy_dict['min_filesize'] = \
utils.to_string(copy_dict['min_filesize']) + \
copy_dict['min_filesize_unit']
if copy_dict['max_filesize']:
copy_dict['max_filesize'] = \
utils.to_string(copy_dict['max_filesize']) + \
copy_dict['max_filesize_unit']
def build_limit_rate(self, copy_dict, scheduled_obj):
"""Called by self.parse().
Build the value of the 'limit_rate' option and store it in the options
dictionary.
Args:
copy_dict (dict): Copy of the original options dictionary
scheduled_obj (media.Scheduled): If a scheduled download is
involved, the corresponding object (so bandwidth limits can be
extracted)
"""
# Set the bandwidth limit (e.g. '50K'). If alternative performance
# limits currently apply, use that limit instead
if self.app_obj.download_manager_obj \
and scheduled_obj \
and scheduled_obj.scheduled_bandwidth_apply_flag:
# The bandwidth limit is divided equally between the workers
limit = int(
scheduled_obj.scheduled_bandwidth
/ len(self.app_obj.download_manager_obj.worker_list)
)
copy_dict['limit_rate'] = str(limit) + 'K'
elif self.app_obj.download_manager_obj \
and self.app_obj.download_manager_obj.alt_limits_flag \
and self.app_obj.alt_bandwidth_apply_flag:
limit = int(
self.app_obj.alt_bandwidth
/ self.app_obj.alt_num_worker
)
copy_dict['limit_rate'] = str(limit) + 'K'
elif self.app_obj.bandwidth_apply_flag:
limit = int(
self.app_obj.bandwidth_default
/ self.app_obj.num_worker_default
)
copy_dict['limit_rate'] = str(limit) + 'K'
def build_proxy(self, copy_dict):
"""Called by self.parse().
Build the value of the 'proxy' option and store it in the options
dictionary.
Args:
copy_dict (dict): Copy of the original options dictionary.
"""
# If the option is already specified, we use it. Otherwise, cycle
# through the proxies in the main appliation's list
if not copy_dict['proxy']:
proxy = self.app_obj.get_proxy()
if proxy is not None:
copy_dict['proxy'] = proxy
def build_dir(self, media_data_obj, copy_dict, operation_type):
"""Called by self.parse().
Finds the directory in which downloaded files are saved.
Args:
media_data_obj (media.Video, media.Channel, media.Playlist,
media.Folder): The media data object being downloaded
copy_dict (dict): Copy of the original options dictionary
operation_type (str): 'sim', 'real', 'custom_sim', 'custom_real',
'classic_sim', 'classic_real', 'classic_custom' (matching
possible values of downloads.DownloadManager.operation_type)
Return values:
The output directory, as a string
"""
override_name = copy_dict['use_fixed_folder']
if operation_type == 'classic_sim' \
or operation_type == 'classic_real' \
or operation_type == 'classic_custom':
# Special case: if a download operation was launched from the
# Classic Mode tab, the directory is specified in that tab
dir_path = media_data_obj.dummy_dir
elif not isinstance(media_data_obj, media.Video) \
and override_name is not None \
and override_name in self.app_obj.media_name_dict:
# Because of the override, save all videos to a system folder
other_dbid = self.app_obj.media_name_dict[override_name]
other_obj = self.app_obj.media_reg_dict[other_dbid]
dir_path = other_obj.get_default_dir(self.app_obj)
elif isinstance(media_data_obj, media.Video):
dir_path = media_data_obj.parent_obj.get_actual_dir(self.app_obj)
else:
dir_path = media_data_obj.get_actual_dir(self.app_obj)
return dir_path
def build_paths(self, dir_path, copy_dict, options_list):
"""Called by self.parse().
Build the --output and --paths options, adding them directly to the
options list.
Args:
dir_path (str): The directory into which files are to be downloaded
copy_dict (dict): Copy of the original options dictionary
options_list (list): List of download options compiled so far; this
function adds options directly to the list
Return values:
The modified options_list
"""
# (When 'output_format_list' is specified, then 'output_format' and
# 'output_template' are ignored. However, 'output_format_list' is
# normally only used with yt-dlp)
if not copy_dict['output_format_list'] \
or self.app_obj.ytdl_fork is None \
or self.app_obj.ytdl_fork != 'yt-dlp' \
or not self.app_obj.ytdlp_filter_options_flag:
# Set the youtube-dl output template for the video's file
template \
= formats.FILE_OUTPUT_CONVERT_DICT[copy_dict['output_format']]
# In the case of copy_dict['output_format'] = 0
if template is None:
template = copy_dict['output_template']
options_list.append('--output')
# (When 'output_path_list' is specified, the template is used
# without a preceding directory path)
if copy_dict['output_path_list']:
options_list.append(template)
else:
options_list.append(
os.path.abspath(os.path.join(dir_path, template)),
)
else:
for item in copy_dict['output_format_list']:
options_list.append('--output')
options_list.append(item)
# Thirdly, set the yt-dlp option 'output_path_list'
if copy_dict['output_path_list']:
for item in copy_dict['output_path_list']:
options_list.append('--paths')
options_list.append(item)
return options_list
def build_video_format(self, media_data_obj, copy_dict, operation_type):
"""Called by self.parse().
Build the value of the 'video_format' and 'all_formats' options and
store them in the options dictionary.
Args:
media_data_obj (media.Video, media.Channel, media.Playlist,
media.Folder): The media data object being downloaded
copy_dict (dict): Copy of the original options dictionary
operation_type (str): 'sim', 'real', 'custom_sim', 'custom_real',
'classic_sim', 'classic_real', 'classic_custom' (matching
possible values of downloads.DownloadManager.operation_type)
"""
if isinstance(media_data_obj, media.Video):
# Special case: if a download operation was launched from the
# Classic Mode tab, the video format may be specified by that tab
if (
operation_type == 'classic_sim' \
or operation_type == 'classic_real' \
or operation_type == 'classic_custom'
) and media_data_obj.dummy_format is not None:
# A string specifying the media format to download, or None if
# the user didn't specify one
# The string is made up of three optional components in a fixed
# order and separated by underlines: 'convert', the video/
# audio format, and the video resolution, for example 'mp4',
# 'mp4_720p', 'convert_mp4_720p'
# Valid values are those specified by formats.VIDEO_FORMAT_LIST
# formats.AUDIO_FORMAT_LIST and formats.VIDEO_RESOLUTION_LIST
convert_flag, this_format, this_res \
= utils.extract_dummy_format(media_data_obj.dummy_format)
if not convert_flag and this_res is None:
# Download the video in the specified format and
# resolution, if available
# Ignore all video/audio formats except the one specified
# by the user in the Classic Mode tab
copy_dict['video_format'] = this_format
copy_dict['all_formats'] = False
copy_dict['video_format_list'] = []
copy_dict['video_format_mode'] = ''
copy_dict['recode_video'] = ''
# v2.1.009: Since the user doesn't have the possibility of
# setting the -f and --merge-output-format options to the
# same value (e.g. 'mp4'), we must do so artificially
copy_dict['merge_output_format'] = this_format
return
elif this_format is not None \
and this_format in formats.VIDEO_FORMAT_DICT:
# Converting video formats requires post-processing
# Ignore all video/audio formats except the one specified
# by the user in the Classic Mode tab
if this_res is None:
copy_dict['video_format'] = '0'
else:
copy_dict['video_format'] \
= 'bestvideo[height<=?' + this_res + ']' \
+ '+bestaudio/best[height<=?' + this_res + ']'
copy_dict['all_formats'] = False
copy_dict['video_format_list'] = []
copy_dict['video_format_mode'] = ''
copy_dict['recode_video'] = this_format
return
elif this_format is not None \
and this_format in formats.AUDIO_FORMAT_DICT:
# Converting audio formats requires post-processing
copy_dict['video_format'] = '0'
copy_dict['all_formats'] = False
copy_dict['video_format_list'] = []
copy_dict['video_format_mode'] = ''
copy_dict['extract_audio'] = True
copy_dict['audio_format'] = this_format
copy_dict['recode_video'] = ''
return
elif this_format is None and this_res is not None:
copy_dict['video_format'] = \
'bestvideo[height<=?' + this_res + ']' \
+ '+bestaudio/best[height<=?' + this_res + ']'
copy_dict['all_formats'] = False
copy_dict['video_format_list'] = []
copy_dict['video_format_mode'] = ''
copy_dict['recode_video'] = ''
# Special case: for simulated downloads, don't specify any video
# formats; if the format isn't available for some videos, we'll get
# an error for each of them (rather than the simulated download we
# were hoping for)
if operation_type == 'sim' \
or operation_type == 'classic_sim' \
or operation_type == 'custom_sim':
copy_dict['video_format'] = '0'
copy_dict['all_formats'] = False
copy_dict['video_format_list'] = []
copy_dict['video_format_mode'] = ''
return
# The 'video_format_list' options contains values corresponding to the
# keys in formats.VIDEO_OPTION_DICT, which are either real extractor
# codes (e.g. '35' representing 'flv [480p]') or dummy extractor
# codes (e.g. 'mp4')
# Some dummy extractor codes are in the form '720p', '1080p60' etc,
# representing progressive scan resolutions. If the user specifies
# at least one of those codes, the first one is used, and all other
# extractor codes are ignored
video_format_list = copy_dict['video_format_list']
resolution_dict = formats.VIDEO_RESOLUTION_DICT.copy()
fps_dict = formats.VIDEO_FPS_DICT.copy()
# If the progressive scan resolution is specified, it overrides all
# other video format options
height = None
fps = None
if self.app_obj.video_res_apply_flag:
height = resolution_dict[self.app_obj.video_res_default]
# (Currently, formats.VIDEO_FPS_DICT only lists formats with 60fps)
if self.app_obj.video_res_default in fps_dict:
fps = fps_dict[self.app_obj.video_res_default]
else:
for item in video_format_list:
if item in resolution_dict:
height = resolution_dict[item]
if item in fps_dict:
fps = fps_dict[item]
break
if height is not None:
# (Currently, formats.VIDEO_FPS_DICT only lists formats with 60fps)
if fps is None:
# Use a youtube-dl argument in the form
# 'bestvideo[height<=?height]+bestaudio/best[height<=height]'
copy_dict['video_format'] = 'bestvideo[height<=?' \
+ str(height) + ']+bestaudio/best[height<=?' + str(height) \
+ ']'
else:
copy_dict['video_format'] = 'bestvideo[height<=?' \
+ str(height) + '][fps<=?' + str(fps) \
+ ']+bestaudio/best[height<=?' + str(height) + ']'
copy_dict['all_formats'] = False
copy_dict['video_format_list'] = []
copy_dict['video_format_mode'] = ''
# Not using a progressive scan resolution
elif video_format_list:
video_format_mode = copy_dict['video_format_mode']
if video_format_mode == 'all':
copy_dict['video_format'] = 0
copy_dict['all_formats'] = True
else:
copy_dict['all_formats'] = False
if video_format_mode == 'single_agree':
char = '/'
elif video_format_mode == 'multiple':
char = ','
else:
# mode is 'single'
char = '+'
copy_dict['video_format'] = char.join(video_format_list)
copy_dict['video_format_list'] = []
copy_dict['video_format_mode'] = ''
class OptionHolder(object):
"""Called from options.OptionsParser.__init__().
The options parser object converts the download options specified by an
options.OptionsManager object into a list of youtube-dl command line
options, whenever required.
Each option has a name, a command line switch, a default value and an
optional list of requirements; they are stored together in an instance of
this object.
Args:
name (str): Option name. Must be a valid option name from the
optionsmanager.OptionsManager class (see the list in at the
beginning of the options.OptionsManager class)
switch (str): 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
as the corresponding option from the optionsmanager.OptionsManager
class.
requirement_list (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. If there are no requirements, the
IV is set to None. (For example 'subs_lang' needs the 'write_subs'
option to be enabled.)
"""
# Standard class methods
def __init__(self, name, switch, default_value, requirement_list=None):
# IV list - other
# ---------------
self.name = name
self.switch = switch
self.default_value = default_value
self.requirement_list = requirement_list
# Public class methods
def check_requirements(self, copy_dict):
"""Called by options.OptionsParser.parse().
Check if options required by another option are enabled, or not.
Args:
copy_dict (dict): Copy of the original options dictionary.
Returns:
True if any of the required options is enabled, otherwise returns
False.
"""
if not self.requirement_list:
return True
return any([copy_dict[req] for req in self.requirement_list])
def is_boolean(self):
"""Called by options.OptionsParser.parse().
Returns:
True if the option is a boolean switch, otherwise returns False
"""
return type(self.default_value) is bool