From b67e4daddbf14a539d23a21415f24b01281d4c69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaime=20Marqui=CC=81nez=20Ferra=CC=81ndiz?= Date: Fri, 18 Mar 2016 19:02:09 +0100 Subject: [PATCH] Allow passing different options to each extractor Currently it can only be done through python and only affects the extractors, not YoutubeDL. --- test/test_YoutubeDL.py | 17 ++++++++++++++ youtube_dl/YoutubeDL.py | 12 +++++++--- youtube_dl/extractor/common.py | 3 ++- youtube_dl/params.py | 43 ++++++++++++++++++++++++++++++++++ 4 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 youtube_dl/params.py diff --git a/test/test_YoutubeDL.py b/test/test_YoutubeDL.py index ca25025e2..d35fb53a0 100644 --- a/test/test_YoutubeDL.py +++ b/test/test_YoutubeDL.py @@ -17,6 +17,7 @@ from youtube_dl.extractor import YoutubeIE from youtube_dl.extractor.common import InfoExtractor from youtube_dl.postprocessor.common import PostProcessor from youtube_dl.utils import ExtractorError, match_filter_func +from youtube_dl.params import Params TEST_URL = 'http://localhost/sample.mp4' @@ -702,6 +703,22 @@ class TestYoutubeDL(unittest.TestCase): downloaded = ydl.downloaded_info_dicts[0] self.assertEqual(downloaded['url'], TEST_URL) + def test_subparams(self): + example_params = {'foo': 'example'} + params = Params({'foo': 'base', 'blah': 'base'}, {'example.com': example_params}) + ydl = YoutubeDL(params) + + class ExampleIE(InfoExtractor): + IE_NAME = 'example.com' + + ie = ExampleIE() + ydl.add_info_extractor(ie) + pars = ie.params + self.assertEqual(pars['foo'], 'example') + self.assertEqual(pars['blah'], 'base') + self.assertEqual(pars.get('blah'), 'base') + self.assertEqual(pars.get('nonexistant'), None) + if __name__ == '__main__': unittest.main() diff --git a/youtube_dl/YoutubeDL.py b/youtube_dl/YoutubeDL.py index d7aa951ff..0c644a3ab 100755 --- a/youtube_dl/YoutubeDL.py +++ b/youtube_dl/YoutubeDL.py @@ -94,6 +94,7 @@ from .postprocessor import ( get_postprocessor, ) from .version import __version__ +from .params import Params if compat_os_name == 'nt': import ctypes @@ -122,7 +123,9 @@ class YoutubeDL(object): options instead. These options are available through the params attribute for the InfoExtractors to use. The YoutubeDL also registers itself as the downloader in charge for the InfoExtractors - that are added to it, so this is a "mutual registration". + that are added to it, so this is a "mutual registration". To use different + parameters in an extractor, the youtube_dl.params.Params class must be + used. Available options: @@ -294,11 +297,14 @@ class YoutubeDL(object): self._num_downloads = 0 self._screen_file = [sys.stdout, sys.stderr][params.get('logtostderr', False)] self._err_file = sys.stderr - self.params = { + if not isinstance(params, Params): + params = Params(params) + self.params = params + default_params = { # Default parameters 'nocheckcertificate': False, } - self.params.update(params) + self.add_extra_info(self.params, default_params) self.cache = Cache(self) if params.get('bidi_workaround', False): diff --git a/youtube_dl/extractor/common.py b/youtube_dl/extractor/common.py index d0bb8d4fe..b932e9eb2 100644 --- a/youtube_dl/extractor/common.py +++ b/youtube_dl/extractor/common.py @@ -53,6 +53,7 @@ from ..utils import ( update_Request, update_url_query, ) +from ..params import ParamsSection class InfoExtractor(object): @@ -331,7 +332,7 @@ class InfoExtractor(object): def set_downloader(self, downloader): """Sets the downloader for this IE.""" self._downloader = downloader - self.params = downloader.params if downloader else {} + self.params = downloader.params.section(self.IE_NAME) if downloader else ParamsSection() def _real_initialize(self): """Real initialization process. Redefine in subclasses.""" diff --git a/youtube_dl/params.py b/youtube_dl/params.py new file mode 100644 index 000000000..03d2f2f2e --- /dev/null +++ b/youtube_dl/params.py @@ -0,0 +1,43 @@ +from __future__ import unicode_literals + + +class Params(dict): + """Params class + + The params class holds the parameters for YoutubeDL objects, in its + simplest form it's initialized with a dictionary with the parameters. To + override some parameter in an info extractor a dictionary can be passed as + the second argument, its keys must match the IE_NAME properties of the + extractors. + """ + def __init__(self, params, sections=None): + super(Params, self).__init__(params) + if sections is None: + sections = {} + self.sections = sections + + def section(self, section): + """Return the params for the specified section""" + return ParamsSection(self.sections.get(section, {}), self) + + +class ParamsSection(object): + def __init__(self, main=None, parent=None): + if main is None: + main = {} + if parent is None: + parent = Params({}) + self.main = main + self.parent = parent + + def __getitem__(self, key): + if key in self.main: + return self.main[key] + else: + return self.parent[key] + + def get(self, key, default=None): + try: + return self[key] + except KeyError: + return default