]> jfr.im git - yt-dlp.git/blobdiff - youtube_dlc/utils.py
Multiple output templates for different file types
[yt-dlp.git] / youtube_dlc / utils.py
index 6740f0cdb494ceb1f8b37effebb4b8cd54b8eec9..987f4bcc084536a51c7b08beaeb1b1a523e9dc8f 100644 (file)
@@ -16,6 +16,7 @@
 import errno
 import functools
 import gzip
+import imp
 import io
 import itertools
 import json
@@ -49,6 +50,7 @@
     compat_html_entities_html5,
     compat_http_client,
     compat_integer_types,
+    compat_numeric_types,
     compat_kwargs,
     compat_os_name,
     compat_parse_qs,
@@ -3672,6 +3674,18 @@ def url_or_none(url):
     return url if re.match(r'^(?:(?:https?|rt(?:m(?:pt?[es]?|fp)|sp[su]?)|mms|ftps?):)?//', url) else None
 
 
+def strftime_or_none(timestamp, date_format, default=None):
+    datetime_object = None
+    try:
+        if isinstance(timestamp, compat_numeric_types):  # unix timestamp
+            datetime_object = datetime.datetime.utcfromtimestamp(timestamp)
+        elif isinstance(timestamp, compat_str):  # assume YYYYMMDD
+            datetime_object = datetime.datetime.strptime(timestamp, '%Y%m%d')
+        return datetime_object.strftime(date_format)
+    except (ValueError, TypeError, AttributeError):
+        return default
+
+
 def parse_duration(s):
     if not isinstance(s, compat_basestring):
         return None
@@ -4155,7 +4169,18 @@ def q(qid):
     return q
 
 
-DEFAULT_OUTTMPL = '%(title)s [%(id)s].%(ext)s'
+DEFAULT_OUTTMPL = {
+    'default': '%(title)s [%(id)s].%(ext)s',
+}
+OUTTMPL_TYPES = {
+    'subtitle': None,
+    'thumbnail': None,
+    'description': 'description',
+    'annotation': 'annotations.xml',
+    'infojson': 'info.json',
+    'pl_description': 'description',
+    'pl_infojson': 'info.json',
+}
 
 
 def limit_length(s, length):
@@ -5905,3 +5930,42 @@ 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
+
+
+def traverse_dict(dictn, keys, casesense=True):
+    if not isinstance(dictn, dict):
+        return None
+    first_key = keys[0]
+    if not casesense:
+        dictn = {key.lower(): val for key, val in dictn.items()}
+        first_key = first_key.lower()
+    value = dictn.get(first_key, None)
+    return value if len(keys) < 2 else traverse_dict(value, keys[1:], casesense)