[vlc-devel] [PATCH 1/4] share: add wrapper script for the YoutubeDL Python module
Rémi Denis-Courmont
remi at remlab.net
Wed Sep 23 17:43:06 CEST 2020
This script generates a M3U playlist from a given URL, providing a
simple serial format that can be read and parsed by another process.
There are in principles two other alternative ways to access it:
1) Calling the YoutubeDL module directly in-process through CPython.
This poses a number of problems:
- CPython must be loaded by the main executable. Python modules will
fail to resolve their CPython symbols otherwise.
- Multiple CPython interpreters are still very immature; GIL behaves
weirdly. CPython is really not meant for multithread.
- The GIL prevents concurrent uses (that's the whole point of it).
- CPython network I/O cannot be interrupted by VLC interruptions, so
the calling thread may get stuck inside CPython.
- A build-time dependency on CPython is added.
2) Parsing the JSON output of the youtube-dl program. This is what MPV
does (through Lua, ironically), but it requires a whole new parser
for the JSON schema. This patch reuses an existing playlist parser.
With a custom Python script, we can decide on the serialisation format
that most suits the usage.
---
share/Makefile.am | 2 +
share/ytdl-extract.py | 102 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 104 insertions(+)
create mode 100755 share/ytdl-extract.py
diff --git a/share/Makefile.am b/share/Makefile.am
index 2373ffbe91..8a92f04360 100644
--- a/share/Makefile.am
+++ b/share/Makefile.am
@@ -49,6 +49,8 @@ nobase_dist_pkgdata_SCRIPTS = \
utils/audio-vlc-default.sh \
utils/video-vlc-default.sh \
$(NULL)
+
+dist_pkgdata_SCRIPTS = ytdl-extract.py
endif
EXTRA_DIST += \
diff --git a/share/ytdl-extract.py b/share/ytdl-extract.py
new file mode 100755
index 0000000000..74b8385d55
--- /dev/null
+++ b/share/ytdl-extract.py
@@ -0,0 +1,102 @@
+#! /usr/bin/python3
+#
+# Copyright (C) 2020 Rémi Denis-Courmont
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+
+import sys
+import youtube_dl
+
+class logger(object):
+ def debug(self, msg):
+ pass
+
+ def warning(self, msg):
+ pass
+
+ def error(self, msg):
+ sys.stderr.write(msg + '\n')
+
+def formats_choose_best(fmts):
+ # Pick our preferred format out of many
+ best_abr = -1
+ best_height = -1
+ best_format = None
+
+ for f in fmts:
+ if 'height' in f and f['height']:
+ height = f['height']
+ else:
+ height = 0
+
+ if height < best_height:
+ continue
+
+ if 'abr' in f and f['abr']:
+ abr = f['abr']
+ else:
+ abr = 0
+
+ if height == best_height or abr < best_abr:
+ continue
+
+ best_abr = abr
+ best_height = height
+ best_format = f
+
+ return best_format
+
+def entry_extract(entry):
+ # Process a given entry of a playlist
+ if 'formats' in entry:
+ fmt = formats_choose_best(entry['formats'])
+ else:
+ fmt = entry
+
+ if 'title' in entry:
+ print('#EXTINF:,,' + entry['title'].splitlines()[0])
+
+ if 'url' in fmt:
+ print('#EXTVLCOPT:no-ytdl') # don't parse recursively
+ print(fmt['url'])
+ else:
+ print('vlc://nop')
+
+def url_extract(url):
+ opts = {
+ 'logger': logger(),
+ 'youtube_include_dash_manifest': False,
+ }
+
+ dl = youtube_dl.YoutubeDL(opts)
+
+ # Process a given URL
+ infos = dl.extract_info(url, download=False)
+
+ print('#EXTM3U')
+
+ if 'title' in infos:
+ print('#PLAYLIST:' + infos['title'].splitlines()[0])
+
+ if 'entries' in infos:
+ # URL is a playlist: iterate over entries
+ for entry in infos['entries']:
+ entry_extract(entry)
+ else:
+ # URL is a single media
+ entry_extract(infos)
+
+
+url_extract(sys.argv[1])
--
2.28.0
More information about the vlc-devel
mailing list