]> jfr.im git - yt-dlp.git/commitdiff
Plugin support
authorpukkandan <redacted>
Sun, 24 Jan 2021 13:40:02 +0000 (19:10 +0530)
committerpukkandan <redacted>
Sun, 24 Jan 2021 14:54:07 +0000 (20:24 +0530)
Extractor plugins are loaded from <root-dir>/ytdlp_plugins/extractor/__init__.py

Inspired by https://github.com/un-def/dl-plus

:ci skip dl

.gitignore
README.md
make_win.bat
youtube_dlc/YoutubeDL.py
youtube_dlc/extractor/__init__.py
youtube_dlc/options.py
youtube_dlc/utils.py
ytdlp_plugins/extractor/__init__.py [new file with mode: 0644]
ytdlp_plugins/extractor/sample.py [new file with mode: 0644]

index 9ee6e91cf7b5954735888b25234ec835441fbdbd..189ada254bcb37a9be687a0b784d6acd29a2811a 100644 (file)
@@ -65,6 +65,14 @@ venv/
 # VS Code related files
 .vscode
 
+# SublimeText files
+*.sublime-workspace
+
+# Cookies
+cookies
 cookies.txt
 
-*.sublime-workspace
\ No newline at end of file
+# Plugins
+ytdlp_plugins/extractor/*
+!ytdlp_plugins/extractor/__init__.py
+!ytdlp_plugins/extractor/sample.py
\ No newline at end of file
index a2ddc3db5f2c2814ec082077a6f2642e7ebe617d..59999245bf74f61726ba844292a74684844a9ff4 100644 (file)
--- a/README.md
+++ b/README.md
@@ -40,6 +40,7 @@ # YT-DLP
     * [Filtering Formats](#filtering-formats)
     * [Sorting Formats](#sorting-formats)
     * [Format Selection examples](#format-selection-examples)
+* [PLUGINS](#plugins)
 * [MORE](#more)
 
 
@@ -1082,9 +1083,11 @@ # prefering better codec and then larger total bitrate for the same resolution
 $ youtube-dlc -S '+res:480,codec,br'
 ```
 
+# PLUGINS
 
+Plugins are loaded from `<root-dir>/ytdlp_plugins/<type>/__init__.py`. Currently only `extractor` plugins are supported. Support for `downloader` and `postprocessor` plugins may be added in the future. See [ytdlp_plugins](ytdlp_plugins) for example.
 
-
+**Note**: `<root-dir>` is the directory of the binary (`<root-dir>/youtube-dlc`), or the root directory of the module if you are running directly from source-code ((`<root dir>/youtube_dlc/__main__.py`)
 
 # MORE
 For FAQ, Developer Instructions etc., see the [original README](https://github.com/ytdl-org/youtube-dl)
index c35d9937e40defce2fc868672be06fb7a313906b..a3d98155ba33146479f49e195340f2532360cfc7 100644 (file)
@@ -1 +1 @@
-py -m PyInstaller youtube_dlc\__main__.py --onefile --name youtube-dlc --version-file win\ver.txt --icon win\icon\cloud.ico --upx-exclude=vcruntime140.dll
\ No newline at end of file
+py -m PyInstaller youtube_dlc\__main__.py --onefile --name youtube-dlc --version-file win\ver.txt --icon win\icon\cloud.ico --upx-exclude=vcruntime140.dll --exclude-module ytdlp_plugins
\ No newline at end of file
index b45b1bbbad365e276a7922f088dcf5d5a3008916..02cc97625933fb260d932650f19cd37ab03995fb 100644 (file)
     process_communicate_or_kill,
 )
 from .cache import Cache
-from .extractor import get_info_extractor, gen_extractor_classes, _LAZY_LOADER
+from .extractor import get_info_extractor, gen_extractor_classes, _LAZY_LOADER, _PLUGIN_CLASSES
 from .extractor.openload import PhantomJSwrapper
 from .downloader import get_suitable_downloader
 from .downloader.rtmp import rtmpdump_version
@@ -2652,9 +2652,12 @@ def print_debug_header(self):
                 self.get_encoding()))
         write_string(encoding_str, encoding=None)
 
-        self._write_string('[debug] yt-dlp version ' + __version__ + '\n')
+        self._write_string('[debug] yt-dlp version %s\n' % __version__)
         if _LAZY_LOADER:
-            self._write_string('[debug] Lazy loading extractors enabled' + '\n')
+            self._write_string('[debug] Lazy loading extractors enabled\n')
+        if _PLUGIN_CLASSES:
+            self._write_string(
+                '[debug] Plugin Extractors: %s\n' % [ie.ie_key() for ie in _PLUGIN_CLASSES])
         try:
             sp = subprocess.Popen(
                 ['git', 'rev-parse', '--short', 'HEAD'],
@@ -2663,7 +2666,7 @@ def print_debug_header(self):
             out, err = process_communicate_or_kill(sp)
             out = out.decode().strip()
             if re.match('[0-9a-f]+', out):
-                self._write_string('[debug] Git HEAD: ' + out + '\n')
+                self._write_string('[debug] Git HEAD: %s\n' % out)
         except Exception:
             try:
                 sys.exc_clear()
index 18d8dbcd6672f82776a9bd9f6f4cc63cac91129d..56251384d8f822c003cc9b86fb61223ab446efa9 100644 (file)
@@ -1,13 +1,19 @@
 from __future__ import unicode_literals
 
+from ..utils import load_plugins
+
 try:
     from .lazy_extractors import *
     from .lazy_extractors import _ALL_CLASSES
     _LAZY_LOADER = True
+    _PLUGIN_CLASSES = []
+
 except ImportError:
     _LAZY_LOADER = False
     from .extractors import *
 
+    _PLUGIN_CLASSES = load_plugins('extractor', 'IE', globals())
+
     _ALL_CLASSES = [
         klass
         for name, klass in globals().items()
index 7a18f0f847dede283ad9eaab89d8afb788bf6d75..97e8964d610b1400662d973513bcdf8efbecee2a 100644 (file)
@@ -15,6 +15,7 @@
 )
 from .utils import (
     expand_path,
+    get_executable_path,
     preferredencoding,
     write_string,
 )
@@ -1226,13 +1227,7 @@ def read_options(path, user=False):
                     return [], None
                 return config, current_path
 
-            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)
-
-            configs['portable'], paths['portable'] = read_options(get_portable_path())
+            configs['portable'], paths['portable'] = read_options(get_executable_path())
             if '--ignore-config' in configs['portable']:
                 return
 
index 6740f0cdb494ceb1f8b37effebb4b8cd54b8eec9..34a14424ac49ac5adf7353bfde12173090e935a1 100644 (file)
@@ -16,6 +16,7 @@
 import errno
 import functools
 import gzip
+import imp
 import io
 import itertools
 import json
@@ -5905,3 +5906,31 @@ def make_dir(path, to_screen=None):
         if callable(to_screen) is not None:
             to_screen('unable to create directory ' + error_to_compat_str(err))
         return False
+
+
+def get_executable_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)
+
+
+def load_plugins(name, type, namespace):
+    plugin_info = [None]
+    classes = []
+    try:
+        plugin_info = imp.find_module(
+            name, [os.path.join(get_executable_path(), 'ytdlp_plugins')])
+        plugins = imp.load_module(name, *plugin_info)
+        for name in dir(plugins):
+            if not name.endswith(type):
+                continue
+            klass = getattr(plugins, name)
+            classes.append(klass)
+            namespace[name] = klass
+    except ImportError:
+        pass
+    finally:
+        if plugin_info[0] is not None:
+            plugin_info[0].close()
+    return classes
diff --git a/ytdlp_plugins/extractor/__init__.py b/ytdlp_plugins/extractor/__init__.py
new file mode 100644 (file)
index 0000000..e1a83b9
--- /dev/null
@@ -0,0 +1,2 @@
+# flake8: noqa
+from .sample import SamplePluginIE
diff --git a/ytdlp_plugins/extractor/sample.py b/ytdlp_plugins/extractor/sample.py
new file mode 100644 (file)
index 0000000..41954b6
--- /dev/null
@@ -0,0 +1,12 @@
+from __future__ import unicode_literals
+
+from youtube_dlc.extractor.common import InfoExtractor
+
+
+class SamplePluginIE(InfoExtractor):
+    _WORKING = False
+    IE_DESC = False
+    _VALID_URL = r'^sampleplugin:'
+
+    def _real_extract(self, url):
+        self.to_screen('URL "%s" sucessfully captured' % url)