Compare commits

...

17 Commits

Author SHA1 Message Date
Tibor Baksa 34e39eb3c1 Update video streams 2023-11-18 00:57:32 +01:00
Tibor Baksa bce8b7ca8f Prepend protocol to stream URL when not provided 2023-11-18 00:50:09 +01:00
Tibor Baksa 62565c10f2 Check if parsing the player page before finding the player options 2023-11-18 00:45:21 +01:00
Tibor Baksa f340ef11af Update title in README 2023-11-18 00:45:10 +01:00
Tibor Baksa 7a27725d6d Add all HLS playlist items from player options 2022-11-22 21:22:09 +01:00
Tibor Baksa f81cadd6d1 Create separate playlist item for player URL and send referrer 2022-11-22 20:55:07 +01:00
Tibor Baksa 8b6793c6a7 Moved section about addons.videolan.org to the end of the README 2018-09-11 00:42:03 +02:00
Tibor Baksa eb59a03590 Added section about availability on addons.videolan.org
Removed note about VLC 3.0
2018-09-11 00:26:07 +02:00
Tibor Baksa 3a497b8630 Rewritten parser logic to handle both streams and videos on the same page 2018-09-10 23:55:10 +02:00
Tibor Baksa 42484060ae Changed noPlaylist to return nothing 2017-09-11 23:46:19 +02:00
Tibor Baksa 705f7b63a2 Added extra check to probe() for the player URL 2017-09-11 23:39:34 +02:00
Tibor Baksa 0e1d10fc0c Changed arturl to be normalized and removed unneeded url property from playlist item 2017-09-10 17:25:10 +02:00
Tibor Baksa b15dc2be32 Changed patterns to be more generic 2017-09-10 17:22:25 +02:00
Tibor Baksa 27a6a17c07 Fixed live stream parsers
Live streams were incorrecntly parsed with a video parser, now live streams have priority over video parsers to prevent this issue
2017-09-10 15:47:49 +02:00
Tibor Baksa a8b5607639 Removed unneeded trailing slashes from URL patterns 2017-09-10 01:45:04 +02:00
Tibor Baksa 3d0cf7e805 Implemented support for multiple videos on one page 2017-09-10 01:12:14 +02:00
Tibor Baksa 9f9331752e Changed URL patterns to find embedded videos in news articles 2017-09-09 23:52:22 +02:00
2 changed files with 138 additions and 157 deletions

View File

@ -1,4 +1,4 @@
# vlc-mediaklikk # vlc-mediaklikk-video
VLC playlist parser for MédiaKlikk videos and video streams VLC playlist parser for MédiaKlikk videos and video streams
## Installation ## Installation
@ -22,11 +22,14 @@ Copy [mediaklikk-video.lua](mediaklikk-video.lua) to [VLC Lua playlist scripts](
* [mediaklikk.hu](https://www.mediaklikk.hu/) * [mediaklikk.hu](https://www.mediaklikk.hu/)
### Video streams ### Video streams
* [M1](https://www.mediaklikk.hu/m1-elo) * [M1](https://hirado.hu/elo/m1)
* [M2](https://www.mediaklikk.hu/m2-elo) * [M2](https://www.mediaklikk.hu/m2-elo)
* [M4](https://www.mediaklikk.hu/m4-elo) * [M4 Sport](https://m4sport.hu/elo/mtv4live)
* [M4 Sport +](https://m4sport.hu/elo/mtv4plus)
* [M5](https://www.mediaklikk.hu/m5-elo) * [M5](https://www.mediaklikk.hu/m5-elo)
* [Duna](https://www.mediaklikk.hu/duna-elo) * [Duna](https://www.mediaklikk.hu/duna-elo)
* [Duna World](https://www.mediaklikk.hu/duna-world-elo) * [Duna World](https://www.mediaklikk.hu/duna-world-elo)
Video streams require VLC 3.0+ (currently available from [nightly builds](https://nightlies.videolan.org/)). ## On addons.videolan.org
This playlist parser is also [available on addons.videolan.org](https://addons.videolan.org/p/1190582/).

View File

@ -1,167 +1,88 @@
local tables local dkjson = require('dkjson')
local streams local log = {}
local urls local openGraph = {}
local log local streams = {}
local tables = {}
local function noPlaylist(reason) local urlPatterns = {
log.err('Failed to create playlist:', reason) 'hirado%.hu',
return {} 'm4sport%.hu',
end 'mediaklikk%.hu'
local Object = {}
function Object:new(overrides)
return setmetatable(overrides or {}, {__index = self})
end
local Parser = Object:new()
local VideoParser = Parser:new()
local LiveStreamParser = Parser:new()
local parsers = {
VideoParser:new{urlPattern = 'hirado%.hu/videok/'},
VideoParser:new{urlPattern = 'm4sport%.hu/videok/'},
VideoParser:new{urlPattern = 'mediaklikk%.hu/video/'},
LiveStreamParser:new{urlPattern = 'mediaklikk%.hu/m1%-elo'},
LiveStreamParser:new{urlPattern = 'mediaklikk%.hu/m2%-elo'},
LiveStreamParser:new{urlPattern = 'mediaklikk%.hu/m4%-elo'},
LiveStreamParser:new{urlPattern = 'mediaklikk%.hu/m5%-elo'},
LiveStreamParser:new{urlPattern = 'mediaklikk%.hu/duna%-elo'},
LiveStreamParser:new{urlPattern = 'mediaklikk%.hu/duna%-world%-elo'}
} }
function probe() function probe()
return tables.some(Parser.probe, parsers) return vlc.access:match('https?') and tables.find(urlPatterns, function(pattern)
return vlc.path:match(pattern)
end)
end end
function parse() function parse()
local parser = tables.find(Parser.probe, parsers)
if not parser then
return noPlaylist('could not find Parser')
end
return parser:parse()
end
local protocol = vlc.access .. '://'
function Parser:probe()
return vlc.access:match('https?') and vlc.path:match(self.urlPattern)
end
function Parser:parse()
local pageSource = streams.readAll(vlc) local pageSource = streams.readAll(vlc)
log.dbg('Extracting Player URL...') if vlc.path:match('player%.mediaklikk%.hu') then
log.dbg('Player loaded, finding player options json')
local playerUrl = self:playerUrl(pageSource) local playerOptionsJson = pageSource:match('pl.setup%( (%b{}) %);')
if not playerUrl then if not playerOptionsJson then
return noPlaylist('could not find Player URL') log.warn('Cannot find player options json')
end return nil
log.dbg('Player URL:', playerUrl)
log.dbg('Extracting Path...')
local path = self:path(playerUrl)
if not path then
return noPlaylist('could not find Path')
end
log.dbg('Path:', path)
return {self:playListItem(path, pageSource)}
end
function Parser:path(playerUrl)
local playerPageSource = streams.readAll(vlc.stream(playerUrl))
local path = playerPageSource:match('"file": *"([^"]+)"')
if path then
return urls.normalize(path)
end
end
function VideoParser:playerUrl(pageSource)
local token = pageSource:match('"token":"([^"]+)"')
if token then
return protocol .. 'player.mediaklikk.hu/player/player-external-vod-full.php?hls=1&token=' .. token
end
end
function VideoParser:playListItem(path, pageSource)
local function findProperty(property)
return pageSource:match('<meta property="og:' .. property .. '" content="([^"]+)"/>')
end
return {
path = path,
title = findProperty('title'),
description = findProperty('description'),
arturl = findProperty('image'),
url = findProperty('url')
}
end
function LiveStreamParser:playerUrl(pageSource)
local streamId = pageSource:match('"streamId":"([^"]+)"')
if streamId then
return protocol .. 'player.mediaklikk.hu/playernew/player.php?noflash=yes&video=' .. streamId
end
end
function LiveStreamParser:playListItem(path, pageSource)
return {
path = path,
title = pageSource:match('<title>(.+)</title>'),
url = protocol .. vlc.path
}
end
tables = {
find = function(predicate, values)
for key, value in ipairs(values) do
if predicate(value, key, values) then
return value, key
end
end end
end,
some = function(predicate, values) log.dbg('Finding playlist items of type hls')
local value, key = tables.find(predicate, values)
return key
end,
collect = function(iterator, state, initialValue) local playerOptions = dkjson.decode(playerOptionsJson)
local result = {} local playlistItems = tables.filter(playerOptions.playlist, function(playlistItem)
for value in iterator, state, initialValue do return playlistItem.type == 'hls'
table.insert(result, value) end)
log.dbg('Number of playlist items:', #playlistItems)
local params = tables.map(tables.toMap(vlc.path:gmatch('[?&]([^=]+)=([^&]*)')), function(param)
return vlc.strings.decode_uri(param)
end)
return tables.map(playlistItems, function(playlistItem)
return {
path = playlistItem.file:gsub('^//', vlc.access .. '://'),
title = params.title,
arturl = params.bgimage
}
end)
end
log.dbg('Finding embedded players');
local playerSetupJsons = tables.toArray(pageSource:gmatch('mtva_player_manager%.player%(document%.getElementById%("player_%d+_%d+"%), (%b{})%);'));
log.dbg('Number of players:', #playerSetupJsons)
return tables.map(playerSetupJsons, function(playerSetupJson)
local playerSetup = dkjson.decode(playerSetupJson)
local video = playerSetup.streamId or playerSetup.token
if not video then
log.warn('Cannot find either streamId or token in player setup json:', playerSetupJson)
return nil
end end
return result
end
}
streams = { local title = playerSetup.title or openGraph.property(pageSource, 'title')
lines = function(s) local arturl = (playerSetup.bgImage and vlc.access .. ':' .. playerSetup.bgImage) or openGraph.property(pageSource, 'image')
return s.readline, s, nil local playerUrl = vlc.access .. '://player.mediaklikk.hu/playernew/player.php?video=' .. video ..
end, ((title and '&title=' .. vlc.strings.encode_uri_component(title)) or '') ..
((arturl and '&bgimage=' .. vlc.strings.encode_uri_component(arturl)) or '')
readAll = function(s) log.dbg('Loading player:', playerUrl)
return table.concat(tables.collect(streams.lines(s)), '\n')
end
}
urls = { return {
normalizations = { path = playerUrl,
{pattern = '\\(.)', replacement = '%1'}, title = title,
{pattern = '^//', replacement = protocol} arturl = arturl,
}, options = {
'http-referrer=' .. vlc.access .. '://' .. vlc.path
normalize = function(url) }
for i, normalization in ipairs(urls.normalizations) do }
url = url:gsub(normalization.pattern, normalization.replacement) end)
end end
return url
end
}
local function logger(vlcLog) local function logger(vlcLog)
return function(...) return function(...)
@ -169,9 +90,66 @@ local function logger(vlcLog)
end end
end end
log = { log.dbg = logger(vlc.msg.dbg)
dbg = logger(vlc.msg.dbg), log.warn = logger(vlc.msg.warn)
warn = logger(vlc.msg.warn), log.err = logger(vlc.msg.err)
err = logger(vlc.msg.err), log.info = logger(vlc.msg.info)
info = logger(vlc.msg.info)
} function openGraph.property(source, property)
return source:match('<meta property="og:' .. property .. '" content="(.-)"/>')
end
function streams.readAll(s)
local function iterator(size)
if s == vlc then
return s.read(size)
else
return s:read(size)
end
end
return table.concat(tables.toArray(iterator, 1024, nil));
end
function tables.find(values, predicate)
for key, value in pairs(values) do
if predicate(value, key, values) then
return value, key
end
end
end
function tables.toArray(iterator, state, initialValue)
local result = {}
for value in iterator, state, initialValue do
table.insert(result, value)
end
return result
end
function tables.toMap(iterator, state, initialValue)
local result = {}
for key, value in iterator, state, initialValue do
result[key] = value
end
return result
end
function tables.map(values, transform)
local result = {}
for key, value in pairs(values) do
result[key] = transform(value, key, values)
end
return result
end
function tables.filter(values, predicate)
local result = {}
for key, value in pairs(values) do
if predicate(value, key, values) then
result[key] = value
end
end
return result
end