If you're looking for a fix, see fork https://gist.github.com/p3g4asus/597050997e01f8fd1fcf473fe6545a4f
It works around this by using youtube-dl, since the lua http interface for VLC is not expressive enough to create a proper fix.
If you're looking for a fix, see fork https://gist.github.com/p3g4asus/597050997e01f8fd1fcf473fe6545a4f
It works around this by using youtube-dl, since the lua http interface for VLC is not expressive enough to create a proper fix.
--[[ | |
Youtube playlist importer for VLC media player 1.1 and 2.0 | |
Copyright 2012 Guillaume Le Maout | |
Authors: Guillaume Le Maout | |
Contact: http://addons.videolan.org/messages/?action=newmessage&username=exebetche | |
This program is free software; you can redistribute it and/or modify | |
it under the terms of the GNU General Public License as published by | |
the Free Software Foundation; either version 2 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 General Public License for more details. | |
You should have received a copy of the GNU 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. | |
--]] | |
--[[ | |
MODified by Kai Gillmann, 19.01.2013, kaigillmann@googlemail.com: | |
VLC HAS already a youtube importer, but not for playlists. IMO this mentioned one is | |
better than this one, because it opens the video in the best possible video resolution. | |
So i decided to remove all parts of the code which is not responsible for list handling. | |
Now this lua script parses the list, as wanted, but for each video opened, the vlc default | |
Youtube script is used, so the videos will be displayed properly. | |
--]] | |
--[[ | |
Patched by Aaron Hill (https://github.com/seraku24), 2018-05-16: | |
The original script was failing in VLC 3.x due to an overzealous probe function. | |
This patch makes the probe function more restrictive to avoid false positives. | |
--]] | |
-- Helper function to get a parameter's value in a URL | |
function get_url_param( url, name ) | |
local _, _, res = string.find( url, "[&?]"..name.."=([^&]*)" ) | |
return res | |
end | |
-- Probe function. | |
function probe() | |
if vlc.access ~= "http" and vlc.access ~= "https" then | |
return false | |
end | |
return string.match(vlc.path:match("([^/]+)"),"%w+.youtube.com") and ( | |
not string.match(vlc.path, "list_ajax") and string.match(vlc.path, "[?&]list=")) | |
end | |
-- Parse function. | |
function parse() | |
if string.match( vlc.path, "list=" ) then | |
local playlist_parsed, playlistData, line, s, item | |
local p = {} | |
local id_ref = {} | |
local index = 0 | |
local playlistID = get_url_param( vlc.path, "list" ) | |
local videoID = get_url_param( vlc.path, "v" ) | |
local playlistURL = "https://www.youtube.com/list_ajax?action_get_list=1&style=xml&list="..playlistID | |
local prevLoaded = 0 | |
while true do | |
playlistData = "" | |
line = "" | |
s = nil | |
s = vlc.stream(playlistURL.."&index="..index) | |
while line do | |
playlistData = playlistData..line | |
line = s:readline() | |
end | |
playlist_parsed = nil | |
playlist_parsed = parse_xml(playlistData).root.video | |
if playlist_parsed == nil then | |
playlist_parsed = {} | |
end | |
for i, video in ipairs(playlist_parsed) do | |
if not id_ref[video.encrypted_id.CDATA] then | |
vlc.msg.dbg(i.." "..video.encrypted_id.CDATA) | |
id_ref[video.encrypted_id.CDATA] = true | |
item = nil | |
item = {} | |
if video.encrypted_id | |
and video.encrypted_id.CDATA then | |
item.path = "http://www.youtube.com/watch?v="..video.encrypted_id.CDATA | |
end | |
if video.title | |
and video.title.CDATA then | |
item.title = video.title.CDATA | |
end | |
if video.artist | |
and video.artist.CDATA then | |
item.artist = video.artist.CDATA | |
end | |
if video.thumbnail | |
and video.thumbnail.CDATA then | |
item.arturl = video.thumbnail.CDATA | |
end | |
if video.description | |
and video.description.CDATA then | |
item.description = video.description.CDATA | |
end | |
--~ item.rating = video.rating | |
table.insert (p, item) | |
end | |
end | |
if #p > prevLoaded or index == 100 then | |
vlc.msg.dbg("Playlist-Youtube: Loaded " ..#p.. " videos...") | |
index = index + 100 | |
prevLoaded = #p | |
else | |
vlc.msg.dbg("Playlist-Youtube: Finished loading " ..#p.. " videos!") | |
return p | |
end | |
end | |
end | |
end | |
function parse_xml(data) | |
local tree = {} | |
local stack = {} | |
local tmp = {} | |
local tmpTag = "" | |
local level = 0 | |
table.insert(stack, tree) | |
for op, tag, attr, empty, val in string.gmatch( | |
data, | |
"<(%p?)([^%s>/]+)([^>]-)(%/?)>[%s\r\n\t]*([^<]*)[%s\r\n\t]*") do | |
if op=="?" then | |
--~ DOCTYPE | |
elseif op=="/" then | |
if level>0 then | |
level = level - 1 | |
table.remove(stack) | |
end | |
else | |
level = level + 1 | |
if op=="!" then | |
stack[level]['CDATA'] = vlc.strings.resolve_xml_special_chars( | |
string.gsub(tag..attr, "%[CDATA%[(.+)%]%]", "%1")) | |
attr = "" | |
level = level - 1 | |
elseif type(stack[level][tag]) == "nil" then | |
stack[level][tag] = {} | |
table.insert(stack, stack[level][tag]) | |
else | |
if type(stack[level][tag][1]) == "nil" then | |
tmp = nil | |
tmp = stack[level][tag] | |
stack[level][tag] = nil | |
stack[level][tag] = {} | |
table.insert(stack[level][tag], tmp) | |
end | |
tmp = nil | |
tmp = {} | |
table.insert(stack[level][tag], tmp) | |
table.insert(stack, tmp) | |
end | |
if val~="" then | |
stack[level][tag]['CDATA'] = {} | |
stack[level][tag]['CDATA'] = vlc.strings.resolve_xml_special_chars(val) | |
end | |
if attr ~= "" then | |
stack[level][tag]['ATTR'] = {} | |
string.gsub(attr, | |
"(%w+)=([\"'])(.-)%2", | |
function (name, _, value) | |
stack[level][tag]['ATTR'][name] = value | |
end) | |
end | |
if empty ~= "" then | |
level = level - 1 | |
table.remove(stack) | |
end | |
end | |
end | |
return tree | |
end |
Oh nice find. This API is apparently still open for both the desktop and mobile domain. Quick tests show it'll work just fine, even without cookies. You do need custom headers though with stuff extractred from the page (take a look at yt_getRequestHeadersYoutube without the cookie parameter).
Then, in javascript terms, the following returns the correct result you can parse:fetch("https://youtube.com/playlist?ctoken=" + conToken + "&pbj=1", { method: "GET", headers: yt_getRequestHeadersYoutube("application/x-www-form-urlencoded", false) });Pretty easy. Although I wouldn't trust on it working forever, since they seem to be moving towards a different interface now (same but with POST, with a generic key in the query and the conToken in the body).
Unfortunately even this type of GET is impossible to reproduce with vlc lua API. I just realized that it supports only customizing referrer and user agent in http GET requests. And unfortunately additional x-youtube headers are mandatory. GET requests without them do not work. Would it be possible to make a simple GET request to FlagPlayer web interface to obtain youtube playlist details in json format?
Thanks in advance
That is quite worrying. I'd recommend creating an issue on VLC to try to fix this, because setting headers should really be in their radar.
Technically you could write a server that does these requests for you, but it'd be a lot of rewriting for the one I'm using and I'd have to open it up to other sources, which is generally a bad idea for puplic cors servers which so many options enabled as I have.
And finally, even if you did, YouTube has IP matching protection enabled on some copyrighted videos - VLC wouldnt be able to play back the URL you get, which means you'd have to stream the audio/video file over that server as well.
While there is really no sensible reason hlto have a separate server running for a host application like VLC. For a website, sure, they have unavoidable restrictions set by the browser, but in this case I'd push towards VLC improving their web request interface.
Oh nice find. This API is apparently still open for both the desktop and mobile domain. Quick tests show it'll work just fine, even without cookies. You do need custom headers though with stuff extractred from the page (take a look at yt_getRequestHeadersYoutube without the cookie parameter).
Then, in javascript terms, the following returns the correct result you can parse:fetch("https://youtube.com/playlist?ctoken=" + conToken + "&pbj=1", { method: "GET", headers: yt_getRequestHeadersYoutube("application/x-www-form-urlencoded", false) });Pretty easy. Although I wouldn't trust on it working forever, since they seem to be moving towards a different interface now (same but with POST, with a generic key in the query and the conToken in the body).
Unfortunately even this type of GET is impossible to reproduce with vlc lua API. I just realized that it supports only customizing referrer and user agent in http GET requests. And unfortunately additional x-youtube headers are mandatory. GET requests without them do not work. Would it be possible to make a simple GET request to FlagPlayer web interface to obtain youtube playlist details in json format?
Thanks in advanceThat is quite worrying. I'd recommend creating an issue on VLC to try to fix this, because setting headers should really be in their radar.
Technically you could write a server that does these requests for you, but it'd be a lot of rewriting for the one I'm using and I'd have to open it up to other sources, which is generally a bad idea for puplic cors servers which so many options enabled as I have.
And finally, even if you did, YouTube has IP matching protection enabled on some copyrighted videos - VLC wouldnt be able to play back the URL you get, which means you'd have to stream the audio/video file over that server as well.
While there is really no sensible reason hlto have a separate server running for a host application like VLC. For a website, sure, they have unavoidable restrictions set by the browser, but in this case I'd push towards VLC improving their web request interface.
You are definitely right. I did not think about the implications my request would have. VLC http interface should definitely be extended to support at least setting headers. Before they add that support, playing youtube palylist will be nearly impossible.
The only way I can think of is using os.execute()
api to execute:
youtube-dl -j --flat-playlist "https://<yourYoutubePlaylist>" > outfile.txt
and parsing outfile.txt
Obviously it will be ugly, slow and it will need youtube-dl.exe to be copied in the same dir as the lua playlist plugin file. But it should work. I will try this solution and I will post it when ready.
Here you can find the updated version of this playlist script.
Disclaimer: this version works only under Windows. It can be easily ported but I have no way to test it on other OS at the moment.
Installation (under Windows): place this file in the lua playlist vlc folder together with JSON.lua and youtube-dl.exe
Looking good, will try it out later and somehow attempt to forward everyone there.
(Btw currently there seem to be two copies of the script in there)
@p3g4asus is it broken OR is it due to some youtube api updates recently?
doesn't seem to work for me though..
Stay Strong
@p3g4asus is it broken OR is it due to some youtube api updates recently?
doesn't seem to work for me though..
Stay Strong
It still does work for most videos. I recommend you keep your youtube-dl executable file updated downloading it periodically from its official website
Thank you for testing. Another problem is the POST request. VLC lua api does not support it. Would GET work anyway? If I click show more link in the youtube playlist page for mobile, a GET is sent (for example:
https://m.youtube.com/playlist?ctoken=4qmFsgI8EiRWTFBMOEJ3aXJhTVFMVktlZk02WVl3WHd1YTVnV2tvbVhIcS0aFENBRjZCbEJVT2tOQ1VRJTNEJTNE&pbj=1
) so I assume GET should work anyway. Do you think it can work?Unfortunately even this type of GET is impossible to reproduce with vlc lua API. I just realized that it supports only customizing referrer and user agent in http GET requests. And unfortunately additional x-youtube headers are mandatory. GET requests without them do not work. Would it be possible to make a simple GET request to FlagPlayer web interface to obtain youtube playlist details in json format?
Thanks in advance