-
-
Save Daniel-Mendes/21cff1d94b584769fa05a4905bd272b5 to your computer and use it in GitHub Desktop.
--[[ | |
Youtube playlist parser for VLC media player v1.0.2 | |
Copyright © 2021 Daniel Mendes | |
Author: Daniel Mendes | |
Contact: [email protected] | |
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. | |
--]] | |
-- 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 | |
-- Helper emulating vlc.readline() to work around its failure on | |
-- very long lines (see #24957) | |
function read_long_line() | |
local eol | |
local pos = 0 | |
local len = 32768 | |
repeat | |
len = len * 2 | |
local line = vlc.peek( len ) | |
if not line then return nil end | |
eol = string.find( line, "\n", pos + 1 ) | |
pos = len | |
until eol or len >= 1024 * 1024 -- No EOF detection, loop until limit | |
return vlc.read( eol or len ) | |
end | |
-- Unescape Hexadecimal representation | |
function unescape (s) | |
s = string.gsub(s or '', "\\x(%x%x)", function (h) return string.char(tonumber(h,16)) end) | |
return s | |
end | |
-- convert a duration to seconds | |
function durationInSeconds(duration) | |
local hour, min, sec = string.match(duration, "(%d?%d?):?(%d?%d):(%d%d)") | |
if hour == "" then | |
hour = 0 | |
end | |
if min == "" then | |
min = 0 | |
end | |
if sec == "" then | |
sec = 0 | |
end | |
return hour*60*60 + min*60 + sec | |
end | |
-- Probe function. | |
function probe() | |
if vlc.access == "http" and vlc.access == "https" then | |
return false | |
end | |
return ( ( vlc.access == "http" or vlc.access == "https" ) and ( | |
(( | |
string.match( vlc.path, "^www%.youtube%.com/" ) | |
or string.match( vlc.path, "^music%.youtube%.com/" ) -- out of use | |
) and ( | |
string.match(vlc.path, "[?&]list=") -- video page with playlist | |
or string.match( vlc.path, "/playlist%?" ) -- playlist page | |
)) or | |
string.match( vlc.path, "^consent%.youtube%.com/" ) | |
) ) | |
end | |
-- Parse function. | |
function parse() | |
if string.match( vlc.path, "^consent%.youtube%.com/" ) then | |
vlc.msg.info("type: consent.youtube.com") | |
-- Cookie consent redirection | |
-- Location: https://consent.youtube.com/m?continue=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DXXXXXXXXXXX&gl=FR&m=0&pc=yt&uxe=23983172&hl=fr&src=1 | |
-- Set-Cookie: CONSENT=PENDING+355; expires=Fri, 01-Jan-2038 00:00:00 GMT; path=/; domain=.youtube.com | |
local url = get_url_param( vlc.path, "continue" ) | |
if not url then | |
vlc.msg.err( "Couldn't handle YouTube cookie consent redirection, please check for updates to this script or try disabling HTTP cookie forwarding" ) | |
return { } | |
end | |
return { { path = vlc.strings.decode_uri( url ), options = { ":no-http-forward-cookies" } } } | |
elseif string.match( vlc.path, "^www.youtube.com/playlist%?list=" ) then | |
vlc.msg.info("type: youtube.com/playlist?list=") | |
local playlist = {} | |
local item, lines, line | |
local index = 1 | |
local playlistID = get_url_param( vlc.path, "list" ) | |
while true do | |
lines = "" | |
line = "" | |
while line do | |
lines = lines..line | |
line = read_long_line() | |
if not line then break end | |
end | |
if string.match(lines, 'var ytInitialData = ') then | |
local index_start, index_end, group1, group2, group3 = string.find(lines, '(var ytInitialData = )(.*)(;</script><link rel=)') | |
local json = require('dkjson') | |
local jsonParsed = json.decode (group2) | |
for key, video in ipairs(jsonParsed.contents.twoColumnBrowseResultsRenderer.tabs[1].tabRenderer.content.sectionListRenderer.contents[1].itemSectionRenderer.contents[1].playlistVideoListRenderer.contents) do | |
item = nil | |
item = {} | |
-- If continuation playlist | |
if video.continuationItemRenderer then | |
else | |
item.path = "https://www.youtube.com/watch?v="..video.playlistVideoRenderer.videoId | |
item.title = video.playlistVideoRenderer.title.runs[1].text | |
item.duration = video.playlistVideoRenderer.lengthSeconds | |
item.author = video.playlistVideoRenderer.shortBylineText.runs[1].text | |
item.arturl = video.playlistVideoRenderer.thumbnail.thumbnails[3].url | |
table.insert (playlist, item) | |
end | |
end | |
return playlist | |
end | |
end | |
elseif string.match(vlc.path, "(www.youtube.com/watch?).*([?&]list=)") then | |
vlc.msg.info("type: youtube.com/watch?list=") | |
local playlist = {} | |
local item, lines, line | |
local index = 1 | |
local playlistID = get_url_param( vlc.path, "list" ) | |
local videoID = get_url_param( vlc.path, "v" ) | |
while true do | |
lines = "" | |
line = "" | |
while line do | |
lines = lines..line | |
line = read_long_line() | |
if not line then break end | |
end | |
if string.match(lines, 'var ytInitialData = ') then | |
local index_start, index_end, group1, group2, group3 = string.find(lines, '(var ytInitialData = )(.*)(;</script><script nonce=")') | |
local json = require('dkjson') | |
local jsonParsed = json.decode (group2) | |
for key, video in ipairs(jsonParsed.contents.twoColumnWatchNextResults.playlist.playlist.contents) do | |
item = nil | |
item = {} | |
item.path = "https://www.youtube.com/watch?v="..video.playlistPanelVideoRenderer.videoId | |
item.title = video.playlistPanelVideoRenderer.title.simpleText | |
item.duration = durationInSeconds(video.playlistPanelVideoRenderer.lengthText.simpleText) | |
item.author = video.playlistPanelVideoRenderer.shortBylineText.runs[1].text | |
item.arturl = video.playlistPanelVideoRenderer.thumbnail.thumbnails[4].url | |
table.insert (playlist, item) | |
end | |
return playlist | |
end | |
end | |
elseif string.match( vlc.path, "^music%.youtube%.com/playlist%?list=" ) then | |
vlc.msg.info("type: music.youtube.com/playlist?list=") | |
elseif string.match(vlc.path, "(music.youtube.com/watch?).*([?&]list=)") then | |
vlc.msg.info("type: music.youtube.com/watch?list=") | |
end | |
end |
So is there a version for Playlists over 100/200 videos?
I did not find how to do it, sorry
Thanks! Your script was the one that worked for me after hassling with other generic plain yt-vlc integration scripts, as it started to raise the lua stream error: Couldn't extract youtube video URL, please check for updates to this script
error message. However, resolution seems to be statically fixed at lower settings. Presumably at 240/144.
Thanks! Your script was the one that worked for me after hassling with other generic plain yt-vlc integration scripts, as it started to raise the
lua stream error: Couldn't extract youtube video URL, please check for updates to this script
error message. However, resolution seems to be statically fixed at lower settings. Presumably at 240/144.
Hello, this message doesn't come from my script but from the vlc youtube.lua
this message doesn't come from my script but from the vlc youtube.lua
That's exactly what i'm saying. Maybe by sentence structure caused a misinterpretation for you. Still, The resolution part, is of this script tho.
It's working!
Thanks!
After so many hours of downloading and testing old codes from 2016, I finally found one that adds YouTube playlists to VLC, thanks.
From what I can see, this code can't identify Youtube Music links, if anyone is wanting this, I came up with a silly "trick" that worked for me, just remove the "music." from the beginning of the link.
So is there a version for Playlists over 100/200 videos?