Last active
May 8, 2024 13:27
-
-
Save Daniel-Mendes/21cff1d94b584769fa05a4905bd272b5 to your computer and use it in GitHub Desktop.
VLC: Youtube Playlist Parser
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--[[ | |
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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.