[vlc-devel] [PATCH 1/2] share: add wrapper script for the YoutubeDL Python module

Alexandre Janniaux ajanni at videolabs.io
Sun Sep 20 21:27:00 CEST 2020


Hi,

I very much like the approach with the helper script to use the M3U
parser.

> +    #dl.add_default_info_extractors()

Is the commented line linked to a potential feature to add?

Patchset LGTM.

Regards,
--
Alexandre Janniaux
Videolabs

On Sun, Sep 20, 2020 at 09:57:21PM +0300, Rémi Denis-Courmont wrote:
> 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 output of the youtube-dl program. This is what MPV does.
>    But this requires a whole new parser for the Python syntax.
>
> 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 | 103 ++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 105 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..2d784c5090
> --- /dev/null
> +++ b/share/ytdl-extract.py
> @@ -0,0 +1,103 @@
> +#! /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
> +import urllib.parse
> +
> +class logger(object):
> +    def debug(self, msg):
> +        pass
> +
> +    def warning(self, msg):
> +        pass
> +
> +    def error(self, msg):
> +        sys.stderr.write(msg)
> +
> +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, meta=True):
> +    # 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'])
> +
> +    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(),
> +    }
> +
> +    dl = youtube_dl.YoutubeDL(opts)
> +    #dl.add_default_info_extractors()
> +
> +    # Process a given URL
> +    # TODO: set process=False to handle playlist item one at a time
> +    infos = dl.extract_info(url, process=True, download=False)
> +
> +    print('#EXTM3U')
> +
> +    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
>
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel


More information about the vlc-devel mailing list