Browse Source

ytdl: extract playlist non-recursively ("flat")

This uses the extract-flat mode of YoutubeDL, which skips parsing
individual items within a playlist. We define a dedicated MRL scheme
to track a YoutubeDL playlist item, and parse it only when the item is
actually opened.

This has two benefits:
1) Extracting a playlist is dramatically faster.
2) Expiring media URL can be played even if the playlist is long.

This does *not* solve the remaining problem that expiring URLs cannot
be saved and replayed later.
pull/113/head
Rémi Denis-Courmont 6 years ago
parent
commit
fa78491d58
  1. 30
      modules/demux/ytdl.c
  2. 33
      share/ytdl-extract.py

30
modules/demux/ytdl.c

@ -207,18 +207,10 @@ static void Close(vlc_object_t *obj)
json_free(&sys->json);
}
static int OpenFilter(vlc_object_t *obj)
static int OpenCommon(vlc_object_t *obj)
{
stream_t *s = (stream_t *)obj;
if (s->psz_url == NULL)
return VLC_EGENERIC;
if (strncasecmp(s->psz_url, "http:", 5)
&& strncasecmp(s->psz_url, "https:", 6))
return VLC_EGENERIC;
if (!var_InheritBool(s, "ytdl"))
return VLC_EGENERIC;
struct ytdl_playlist *sys = vlc_obj_malloc(obj, sizeof (*sys));
if (unlikely(sys == NULL))
return VLC_EGENERIC;
@ -257,6 +249,21 @@ static int OpenFilter(vlc_object_t *obj)
return VLC_SUCCESS;
}
static int OpenFilter(vlc_object_t *obj)
{
stream_t *s = (stream_t *)obj;
if (s->psz_url == NULL)
return VLC_EGENERIC;
if (strncasecmp(s->psz_url, "http:", 5)
&& strncasecmp(s->psz_url, "https:", 6))
return VLC_EGENERIC;
if (!var_InheritBool(obj, "ytdl"))
return VLC_EGENERIC;
return OpenCommon(obj);
}
vlc_module_begin()
set_shortname("YT-DL")
set_description("YoutubeDL")
@ -267,4 +274,9 @@ vlc_module_begin()
/* TODO: convert to demux and enable by default */
add_bool("ytdl", false, N_("Enable YT-DL"), N_("Enable YT-DL"), true)
change_safe()
add_submodule()
set_capability("access", 0)
add_shortcut("ytdl")
set_callbacks(OpenCommon, Close)
vlc_module_end()

33
share/ytdl-extract.py

@ -18,6 +18,7 @@
import sys
import json
import urllib.parse
import youtube_dl
class logger(object):
@ -32,6 +33,7 @@ class logger(object):
def url_extract(url):
opts = {
'extract_flat': True,
'logger': logger(),
'youtube_include_dash_manifest': False,
}
@ -40,7 +42,36 @@ def url_extract(url):
# Process a given URL
infos = dl.extract_info(url, download=False)
if 'entries' in infos:
for entry in infos['entries']:
if 'ie_key' in entry and entry['ie_key']:
# Flat-extracted playlist entry
url = 'ytdl:///?' + urllib.parse.urlencode(entry)
entry['url'] = url;
print(json.dumps(infos))
def url_process(ie_url):
opts = {
'logger': logger(),
'youtube_include_dash_manifest': False,
}
dl = youtube_dl.YoutubeDL(opts)
# Rebuild the original IE entry
entry = { }
for p in urllib.parse.parse_qsl(url[9:]):
entry[p[0]] = p[1]
infos = dl.process_ie_result(entry, download=False)
print(json.dumps(infos))
url = sys.argv[1]
url_extract(url)
if url.startswith('ytdl:///?'):
url_process(url)
else:
url_extract(url)

Loading…
Cancel
Save