[vlc-devel] [PATCH] lua: Add Twitch.tv playlist script

Rémi Denis-Courmont remi at remlab.net
Sun Sep 10 11:56:41 CEST 2017


Le 10 septembre 2017 00:16:41 GMT+02:00, Marvin Scholz <epirat07 at gmail.com> a écrit :
>Add a script which can handle twitch.tv stream or video urls
>---
> share/Makefile.am             |   2 +
>share/lua/playlist/twitch.lua | 269
>++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 271 insertions(+)
> create mode 100644 share/lua/playlist/twitch.lua
>
>diff --git a/share/Makefile.am b/share/Makefile.am
>index 82f8da5ac3..773ebf843a 100644
>--- a/share/Makefile.am
>+++ b/share/Makefile.am
>@@ -149,6 +149,7 @@ nobase_vlcdata_DATA += \
> 	lua/playlist/vimeo.luac \
> 	lua/playlist/vocaroo.luac \
> 	lua/playlist/youtube.luac \
>+	lua/playlist/twitch.luac \
> 	lua/sd/fmc.luac \
> 	lua/sd/icecast.luac \
> 	lua/sd/icast.luac \
>@@ -290,6 +291,7 @@ EXTRA_DIST += \
> 	lua/playlist/vimeo.lua \
> 	lua/playlist/vocaroo.lua \
> 	lua/playlist/youtube.lua \
>+	lua/playlist/twitch.lua \
> 	lua/playlist/zapiks.lua \
> 	lua/sd/README.txt \
> 	lua/sd/fmc.lua \
>diff --git a/share/lua/playlist/twitch.lua
>b/share/lua/playlist/twitch.lua
>new file mode 100644
>index 0000000000..519ee21a2c
>--- /dev/null
>+++ b/share/lua/playlist/twitch.lua
>@@ -0,0 +1,269 @@
>+--[[
>+Resolve Twitch channel and video URLs to the actual stream URL
>+
>+ $Id$
>+ Copyright © 2017 the VideoLAN team
>+
>+ Author: Marvin Scholz <epirat07 at gmail dot com>
>+
>+ 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.
>+--]]
>+
>+-- Probe function
>+function probe()
>+    return (vlc.access == "http" or vlc.access == "https")
>+        and ( vlc.path:match("^www%.twitch%.tv/videos/.+") or
>+              vlc.path:match("^www%.twitch%.tv/.+") )
>+end
>+
>+-- Download and parse a JSON document from the specified URL
>+-- Returns: obj, pos, err (see dkjson docs)
>+function parse_json(url)
>+    local json   = require("dkjson")
>+    local stream = vlc.stream(url)
>+    local string = ""
>+    local line   = ""
>+
>+    if not stream then
>+        return nil, nil, "Failed creating VLC stream"
>+    end
>+
>+    while true do
>+        line = stream:readline()
>+
>+        if not line then
>+            break
>+        end
>+
>+        string = string .. line
>+    end
>+
>+    return json.decode(string)
>+end
>+
>+-- Request access token from Twitch
>+-- Returns: token, signature, err
>+function get_access_token(channel)
>+    if (channel == nil or channel == "") then
>+        return nil, nil, "Invalid channel"
>+    end
>+
>+    local url = "https://api.twitch.tv/api/channels/" .. channel ..
>"/access_token?client_id=jzkbprff40iqj646a697cyrvl0zt2m6"
>+    local obj, pos, err = parse_json(url)
>+
>+    if err then
>+        return nil, nil, "Error getting JSON object: " .. err
>+    end
>+
>+    -- In case of error, the API will return an object with
>+    -- error and message given
>+    if obj.error then
>+        local err = "Access token error: " .. obj.error
>+        if obj.message then
>+            err = err .. " (" .. obj.message .. ")"
>+        end
>+        return nil, nil, err
>+    end
>+
>+    -- Check if API response matches expectations (sig and token)
>+    if (obj.token == nil) or (obj.sig == nil) then
>+        return nil, nil, "Access token error: Invalid API response
>(token or sig missing)"
>+    end
>+
>+    return obj.token, obj.sig, nil
>+end
>+
>+-- Request stream info from Twitch
>+-- Returns: obj, err
>+function get_stream_info(channel)
>+    if (channel == nil or channel == "") then
>+        return nil, "Invalid channel"
>+    end
>+
>+    local test = vlc.strings.encode_uri_component("foo%bar")
>+    vlc.msg.err(test)
>+
>+    local url = "https://api.twitch.tv/api/channels/" .. channel ..
>"?client_id=jzkbprff40iqj646a697cyrvl0zt2m6"
>+    local obj, pos, err = parse_json(url)
>+
>+    if err then
>+        return nil, "Error getting JSON object: " .. err
>+    end
>+
>+    -- In case of error, the API will return an object with
>+    -- error and message given
>+    if obj.error then
>+        local err = "Stream info error: " .. obj.error
>+        if obj.message then
>+            err = err .. " (" .. obj.message .. ")"
>+        end
>+        return nil, err
>+    end
>+
>+    return obj, nil
>+end
>+
>+-- Make a request to the Twitch API endpoint given by url
>+-- Returns: obj, err
>+function twitch_api_req(url)
>+    local obj, pos, err = parse_json(url ..
>"?client_id=jzkbprff40iqj646a697cyrvl0zt2m6")
>+
>+    if err then
>+        return nil, "Error getting JSON object: " .. err
>+    end
>+
>+    -- In case of error, the API will return an object with
>+    -- error and message given
>+    if obj.error then
>+        local err = "Twitch API error: " .. obj.error
>+        if obj.message then
>+            err = err .. " (" .. obj.message .. ")"
>+        end
>+        return nil, err
>+    end
>+
>+    return obj, nil
>+end
>+
>+function handle_stream()
>+
>+end
>+
>+-- Parser for twitch video urls
>+function parse_video()
>+    local playlist = {}
>+    local item = {}
>+    local url, obj, err = nil
>+
>+    -- Parse video id out of url
>+    local video_id = vlc.path:match("^www%.twitch%.tv/videos/(.+)")
>+
>+    if video_id == nil then
>+        vlc.msg.err("Twitch: Failed to parse twitch url for video id")
>+        return playlist
>+    end
>+
>+    vlc.msg.dbg("Twitch: Loading video url for " .. video_id)
>+
>+    -- Request video token (required for the video stream)
>+    url = "https://api.twitch.tv/api/vods/" ..  video_id ..
>"/access_token"
>+    obj, err = twitch_api_req(url)
>+
>+    if err then
>+        vlc.msg.err("Error getting request token from Twitch: " ..
>err)
>+        return playlist
>+    end
>+
>+    -- Construct stream url
>+    local stream_url = "http://usher.twitch.tv/vod/" .. video_id
>+    stream_url = stream_url .. "?player=twitchweb"
>+    stream_url = stream_url .. "&nauth=" ..
>vlc.strings.encode_uri_component(obj.token)
>+    stream_url = stream_url .. "&nauthsig=" .. obj.sig
>+    stream_url = stream_url ..
>"&allow_audio_only=true&allow_source=true"
>+
>+    item["path"]   = stream_url
>+
>+    -- Set base information
>+    item["name"]   = "Twitch: " .. video_id
>+
>+    -- Request video information
>+    url = "https://api.twitch.tv/kraken/videos/v" .. video_id
>+    obj, err = twitch_api_req(url)
>+
>+    if err then
>+        vlc.msg.warn("Error getting video info from Twitch: " .. err)
>+        table.insert(playlist, item)
>+        return playlist
>+    end
>+
>+    -- Overwrite with now obtained better info
>+    item["name"]        = "Twitch: " .. obj.title
>+    item["artist"]      = obj.channel.display_name
>+    item["description"] = obj.description
>+    item["url"]         = vlc.path
>+
>+    table.insert(playlist, item)
>+
>+    return playlist
>+end
>+
>+-- Parser for twitch stream urls
>+function parse_stream()
>+    local playlist = {}
>+    local item = {}
>+    local url, obj, err = nil
>+
>+    -- Parse channel name out of url
>+    local channel = vlc.path:match("^www%.twitch%.tv/(.+)")
>+
>+    if channel == nil then
>+        vlc.msg.err("Twitch: Failed to parse twitch url for channel
>name")
>+        return playlist
>+    end
>+
>+    vlc.msg.dbg("Twitch: Loading stream url for " .. channel)
>+
>+    -- Request channel token (required for the stream m3u8)
>+    url = "https://api.twitch.tv/api/channels/" .. channel ..
>"/access_token"
>+    obj, err = twitch_api_req(url)
>+
>+    if err then
>+        vlc.msg.err("Error getting request token from Twitch: " ..
>err)
>+        return playlist
>+    end
>+
>+    -- Construct stream url
>+    local stream_url = "http://usher.twitch.tv/api/channel/hls/" ..
>channel .. ".m3u8"
>+    stream_url = stream_url .. "?player=twitchweb"
>+    stream_url = stream_url .. "&token=" ..
>vlc.strings.encode_uri_component(obj.token)
>+    stream_url = stream_url .. "&sig=" .. obj.sig
>+    stream_url = stream_url ..
>"&allow_audio_only=true&allow_source=true&type=any"
>+
>+    item["path"]   = stream_url
>+
>+    -- Set base information
>+    item["name"]   = "Twitch: " .. channel
>+    item["artist"] = channel
>+
>+    -- Request channel information
>+    url = "https://api.twitch.tv/api/channels/" .. channel
>+    obj, err = twitch_api_req(url)
>+
>+    if err then
>+        vlc.msg.warn("Error getting channel info from Twitch: " ..
>err)
>+        table.insert(playlist, item)
>+        return playlist
>+    end
>+
>+    -- Overwrite with now obtained better info
>+    item["name"]        = "Twitch: " .. obj.display_name
>+    item["nowplaying"]  = obj.display_name .. " playing " .. obj.game
>+    item["artist"]      = obj.display_name
>+    item["description"] = obj.status
>+    item["url"]         = vlc.path
>+
>+    table.insert(playlist, item)
>+
>+    return playlist
>+end
>+
>+-- Parse function
>+function parse()
>+    if vlc.path:match("twitch%.tv/videos/.+") then
>+        return parse_video()
>+    else
>+        return parse_stream()
>+    end
>+end
>-- 
>2.11.0 (Apple Git-81)
>
>_______________________________________________
>vlc-devel mailing list
>To unsubscribe or modify your subscription options:
>https://mailman.videolan.org/listinfo/vlc-devel

Isn't the first pattern match implied by the second one?
-- 
Envoyé de mon appareil Android avec Courriel K-9 Mail. Veuillez excuser ma brièveté.


More information about the vlc-devel mailing list