1
0
mirror of https://github.com/l1ving/youtube-dl synced 2025-03-13 17:47:17 +08:00

Added support for plugin/local extractors.

Currently, creating new extractors is a bit tedious for non developers.
You have to get the source, edit the package and then build it for your distro
(or possibly push the updates upstream). Although this centralized extractor
approach has it's upsides (e.g. more supported sites for everyone), sometimes
you just want to write an extractor quickly for local use.

I've added a system for writing plugin extractors and have them load at runtime.
Extractor classes are placed in .py files in
"$XDG_CONFIG_HOME/youtube-dl/extractors/" or "~/.config/youtube-dl/extractors".
At runtime these files are compiled and executed in an independent global
namespace. This global namespace is scanned for classes ending in "IE", which
are put in the 'youtube_dl.extractor' global namespace, init-ed and returned.

Plugin extractors are placed before regular extractors so that they have
precedence in case of overwrites.
This commit is contained in:
Jashandeep Sohi 2014-11-28 17:18:17 -08:00
parent 93b8a10e3b
commit 3a9192a9d9
3 changed files with 52 additions and 2 deletions

View File

@ -38,7 +38,7 @@ from .update import update_self
from .downloader import (
FileDownloader,
)
from .extractor import gen_extractors
from .extractor import gen_extractors, gen_plugin_extractors
from .YoutubeDL import YoutubeDL
from .postprocessor import (
AtomicParsleyPP,
@ -105,7 +105,13 @@ def _real_main(argv=None):
_enc = preferredencoding()
all_urls = [url.decode(_enc, 'ignore') if isinstance(url, bytes) else url for url in all_urls]
extractors = gen_extractors()
# Load plugin extractors
if os.path.isdir(opts.plugin_extractors_dir) and not opts.ignore_plugin_extractors:
extractors = gen_plugin_extractors(opts.plugin_extractors_dir)
else:
extractors = []
extractors += gen_extractors()
if opts.list_extractors:
for ie in sorted(extractors, key=lambda ie: ie.IE_NAME.lower()):

View File

@ -523,6 +523,7 @@ from .zingmp3 import (
ZingMp3SongIE,
ZingMp3AlbumIE,
)
import os
_ALL_CLASSES = [
klass
@ -538,7 +539,29 @@ def gen_extractors():
"""
return [klass() for klass in _ALL_CLASSES]
def gen_plugin_extractors(plugin_dir, verbosity = False):
""" Return a list of an instance of every plugin extractor found in the
plugin directory. Scan every .py file in plugin_dir for classes with names
ending in 'IE'.
"""
classes = []
for file_ in os.listdir(plugin_dir):
if not file_.endswith(".py"):
continue
file_globals = {}
exec(open(os.path.join(plugin_dir, file_), "r").read(), file_globals)
for name, class_ in file_globals.items():
if name.endswith("IE"):
#Add the class to this modules globals so that get_info_extractor works
globals()[name] = class_
classes.append(class_)
return [class_() for class_ in classes]
def get_info_extractor(ie_name):
"""Returns the info extractor class with the given ie_name"""
return globals()[ie_name + 'IE']

View File

@ -68,6 +68,18 @@ def parseOpts(overrideArguments=None):
return userConf
def _get_default_plugin_extractors_dir():
""" Return the default plugin extractors directory.
If XDG_CONFIG_HOME is set, then the location is XDG_CONFIG_HOME/youtube-dl/extractors,
otherwise it is ~/.config/youtube-dl/extractors.
"""
xdg_config_home = compat_getenv('XDG_CONFIG_HOME')
if xdg_config_home:
return os.path.join(xdg_config_home, 'youtube-dl', 'extractors')
else:
return os.path.join(compat_expanduser('~'), '.config', 'youtube-dl', 'extractors')
def _format_option_string(option):
''' ('-o', '--option') -> -o, --format METAVAR'''
@ -148,6 +160,15 @@ def parseOpts(overrideArguments=None):
'--extractor-descriptions',
action='store_true', dest='list_extractor_descriptions', default=False,
help='Output descriptions of all supported extractors')
general.add_option(
'--plugin-extractors-dir', default=_get_default_plugin_extractors_dir(),
metavar='PATH',
action='store',
help='All .py files in this directory are scanned for extractor classes ending in IE and are loaded. (default: %default)')
general.add_option(
'--ignore-plugin-extractors',
action='store_true', default=False,
help='Do not load extractors in the plugin directory')
general.add_option(
'--proxy', dest='proxy',
default=None, metavar='URL',