]> jfr.im git - yt-dlp.git/commitdiff
Portable Configuration file (closes #19)
authorpukkandan <redacted>
Sat, 16 Jan 2021 18:21:00 +0000 (23:51 +0530)
committerpukkandan <redacted>
Sat, 16 Jan 2021 18:35:46 +0000 (00:05 +0530)
Inspired by https://github.com/ytdl-org/youtube-dl/pull/27592

.gitignore
README.md
youtube_dlc/options.py

index 093d4f2ed84222805beadacfdc9157171d5b1874..744d718f3db190e9cda5decced2da34271d6b048 100644 (file)
@@ -46,6 +46,7 @@ updates_key.pem
 *.swf
 *.part
 *.ytdl
+*.conf
 *.swp
 *.spec
 test/local_parameters.json
index 6081e19314b321b7db19ff655df5f2f6c1cbb235..0b309f4f1d066e8a60456320d4d972681c49ba21 100644 (file)
--- a/README.md
+++ b/README.md
@@ -633,7 +633,20 @@ ## Extractor Options:
 
 # CONFIGURATION
 
-You can configure youtube-dlc by placing any supported command line option to a configuration file. On Linux and macOS, the system wide configuration file is located at `/etc/youtube-dlc.conf` and the user wide configuration file at `~/.config/youtube-dlc/config`. On Windows, the user wide configuration file locations are `%APPDATA%\youtube-dlc\config.txt` or `C:\Users\<user name>\youtube-dlc.conf`. Note that by default configuration file may not exist so you may need to create it yourself.
+You can configure youtube-dlc by placing any supported command line option to a configuration file. The configuration is loaded from the following locations:
+
+1. The file given by `--config-location`
+1. **Portable Configuration**: `yt-dlp.conf` or `youtube-dlc.conf` in the same directory as the bundled binary. If you are running from source-code (`<root dir>/youtube_dlc/__main__.py`), the root directory is used instead.
+1. **User Configuration**:
+    * `%XDG_CONFIG_HOME%/yt-dlp/config` (recommended on Linux/macOS)
+    * `%XDG_CONFIG_HOME%/yt-dlp.conf`
+    * `%APPDATA%/yt-dlp/config` (recommended on Windows)
+    * `%APPDATA%/yt-dlp/config.txt`
+    * `~/yt-dlp.conf`
+    * `~/yt-dlp.conf.txt`
+
+    If none of these files are found, the search is performed again by replacing `yt-dlp` with `youtube-dlc`. Note that `~` points to `C:\Users\<user name>` on windows. Also, `%XDG_CONFIG_HOME%` defaults to `~/.config` if undefined
+1. **System Configuration**: `/etc/yt-dlp.conf` or `/etc/youtube-dlc.conf`
 
 For example, with the following configuration file youtube-dlc will always extract the audio, not copy the mtime, use a proxy and save all videos under `Movies` directory in your home directory:
 ```
@@ -652,11 +665,9 @@ # Save all videos under Movies directory in your home directory
 -o ~/Movies/%(title)s.%(ext)s
 ```
 
-Note that options in configuration file are just the same options aka switches used in regular command line calls thus there **must be no whitespace** after `-` or `--`, e.g. `-o` or `--proxy` but not `- o` or `-- proxy`.
-
-You can use `--ignore-config` if you want to disable the configuration file for a particular youtube-dlc run.
+Note that options in configuration file are just the same options aka switches used in regular command line calls; thus there **must be no whitespace** after `-` or `--`, e.g. `-o` or `--proxy` but not `- o` or `-- proxy`.
 
-You can also use `--config-location` if you want to use custom configuration file for a particular youtube-dlc run.
+You can use `--ignore-config` if you want to disable all configuration files for a particular youtube-dlc run. If `--ignore-config` is found inside any configuration file, no further configuration will be loaded. For example, having the option in the portable configuration file prevents loading of user and system configurations. Additionally, (for backward compatibility) if `--ignore-config` is found inside the system configuration file, the user configuration is not loaded.
 
 ### Authentication with `.netrc` file
 
index 2804186ad24c3a2d3632b5349f6d53ff71013e41..a26b04b4bca2f6b3b96b1ba33f87643a5d0ff3dc 100644 (file)
@@ -54,42 +54,35 @@ def _readOptions(filename_bytes, default=[]):
             optionf.close()
         return res
 
-    def _readUserConf():
-        xdg_config_home = compat_getenv('XDG_CONFIG_HOME')
-        if xdg_config_home:
-            userConfFile = os.path.join(xdg_config_home, 'youtube-dlc', 'config')
-            if not os.path.isfile(userConfFile):
-                userConfFile = os.path.join(xdg_config_home, 'youtube-dlc.conf')
-        else:
-            userConfFile = os.path.join(compat_expanduser('~'), '.config', 'youtube-dlc', 'config')
-            if not os.path.isfile(userConfFile):
-                userConfFile = os.path.join(compat_expanduser('~'), '.config', 'youtube-dlc.conf')
-        userConf = _readOptions(userConfFile, None)
-
-        if userConf is None:
-            appdata_dir = compat_getenv('appdata')
-            if appdata_dir:
-                userConf = _readOptions(
-                    os.path.join(appdata_dir, 'youtube-dlc', 'config'),
-                    default=None)
-                if userConf is None:
-                    userConf = _readOptions(
-                        os.path.join(appdata_dir, 'youtube-dlc', 'config.txt'),
-                        default=None)
+    def _readUserConf(package_name, default=[]):
+        # .config
+        xdg_config_home = compat_getenv('XDG_CONFIG_HOME') or compat_expanduser('~/.config')
+        userConfFile = os.path.join(xdg_config_home, package_name, 'config')
+        if not os.path.isfile(userConfFile):
+            userConfFile = os.path.join(xdg_config_home, '%s.conf' % package_name)
+        userConf = _readOptions(userConfFile, default=None)
+        if userConf is not None:
+            return userConf
 
-        if userConf is None:
-            userConf = _readOptions(
-                os.path.join(compat_expanduser('~'), 'youtube-dlc.conf'),
-                default=None)
-        if userConf is None:
-            userConf = _readOptions(
-                os.path.join(compat_expanduser('~'), 'youtube-dlc.conf.txt'),
-                default=None)
+        # appdata
+        appdata_dir = compat_getenv('appdata')
+        if appdata_dir:
+            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)
+        if userConf is not None:
+            return userConf
 
+        # home
+        userConfFile = os.path.join(compat_expanduser('~'), '%s.conf' % package_name)
+        userConf = _readOptions(userConfFile, default=None)
         if userConf is None:
-            userConf = []
+            userConf = _readOptions('%s.txt' % userConfFile, default=None)
+        if userConf is not None:
+            return userConf
 
-        return userConf
+        return default
 
     def _format_option_string(option):
         ''' ('-o', '--option') -> -o, --format METAVAR'''
@@ -1147,33 +1140,60 @@ def compat_conf(conf):
                 return [a.decode(preferredencoding(), 'replace') for a in conf]
             return conf
 
-        command_line_conf = compat_conf(sys.argv[1:])
-        opts, args = parser.parse_args(command_line_conf)
+        configs = {
+            'command_line': compat_conf(sys.argv[1:]),
+            'custom': [], 'portable': [], 'user': [], 'system': []}
+        opts, args = parser.parse_args(configs['command_line'])
 
-        system_conf = user_conf = custom_conf = []
+        def get_configs():
+            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 '--config-location' in command_line_conf:
-            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)
-            custom_conf = _readOptions(location)
-        elif '--ignore-config' in command_line_conf:
-            pass
-        else:
-            system_conf = _readOptions('/etc/youtube-dlc.conf')
-            if '--ignore-config' not in system_conf:
-                user_conf = _readUserConf()
+            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'))
+
+            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')
+
+            if '--ignore-config' in configs['system']:
+                return
+            configs['user'] = _readUserConf('yt-dlp', default=None)
+            if configs['user'] is None:
+                configs['user'] = _readUserConf('youtube-dlc')
+            if '--ignore-config' in configs['user']:
+                configs['system'] = []
 
-        argv = system_conf + user_conf + custom_conf + command_line_conf
+        get_configs()
+        argv = configs['system'] + configs['user'] + configs['portable'] + configs['custom'] + configs['command_line']
         opts, args = parser.parse_args(argv)
         if opts.verbose:
             for conf_label, conf in (
-                    ('System config', system_conf),
-                    ('User config', user_conf),
-                    ('Custom config', custom_conf),
-                    ('Command-line args', command_line_conf)):
+                    ('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))))
 
     return parser, opts, args