Fix support for arte.tv
[libquvi-scripts.git] / share / media / arte.lua
blobb396eff6f523eb007951e0d0162564257f153ba8
1 -- libquvi-scripts
2 -- Copyright (C) 2013 Mohamed El Morabity <melmorabity@fedoraproject.org>
3 -- Copyright (C) 2012-2013 Toni Gundogdu <legatvs@gmail.com>
4 -- Copyright (C) 2011 Raphaƫl Droz <raphael.droz+floss@gmail.com>
5 --
6 -- This file is part of libquvi-scripts <http://quvi.sourceforge.net/>.
7 --
8 -- This program is free software: you can redistribute it and/or
9 -- modify it under the terms of the GNU Affero General Public
10 -- License as published by the Free Software Foundation, either
11 -- version 3 of the License, or (at your option) any later version.
13 -- This program is distributed in the hope that it will be useful,
14 -- but WITHOUT ANY WARRANTY; without even the implied warranty of
15 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 -- GNU Affero General Public License for more details.
18 -- You should have received a copy of the GNU Affero General
19 -- Public License along with this program. If not, see
20 -- <http://www.gnu.org/licenses/>.
23 -- NOTE: Most videos expire some (7?) days after their original broadcast
25 local Arte = {} -- Utility functions unique to to this script.
27 -- Identify the media script.
28 function ident(qargs)
29 return {
30 can_parse_url = Arte.can_parse_url(qargs),
31 domains = table.concat({'arte.tv'}, ',')
33 end
35 -- Parse media properties.
36 function parse(qargs)
37 local J = require 'json'
39 -- Fetch the video data JSON.
40 local p = quvi.http.fetch(qargs.input_url).data
41 local u = p:match('arte_vp_url="(.-/ALL%.json)"')
42 or error('no match: config URL')
43 local c = quvi.http.fetch(u).data
44 local j = J.decode(c)
46 -- Check the video expiration date.
47 local d = j['videoJsonPlayer']['VRU']
48 if d and Arte.has_expired(d) then
49 error('media no longer available (expired)')
50 end
52 qargs.id = j['videoJsonPlayer']['VPI']
54 qargs.title = j['videoJsonPlayer']['VTI']
56 qargs.thumb_url = j['videoJsonPlayer']['programImage']
58 qargs.duration_ms = j['videoJsonPlayer']['videoDurationSeconds'] * 1000
60 qargs.streams = Arte.iter_streams(j)
62 return qargs
63 end
66 -- Utility functions
69 function Arte.can_parse_url(qargs)
70 local U = require 'socket.url'
71 local t = U.parse(qargs.input_url)
73 if t and t.scheme and t.scheme:lower():match('^http$')
74 and t.host and t.host:lower():match('www.arte%.tv$')
75 and t.path and t.path:lower():match('^/guide/%w+/')
76 then
77 return true
78 else
79 return false
80 end
81 end
83 function Arte.iter_streams(j)
84 local S = require 'quvi/stream'
86 local d = j['videoJsonPlayer']['VSR']
87 local r = {}
89 for _, v in pairs(d) do
90 local s
92 -- Handle available RTMP streams.
93 if v['streamer'] then
94 s = v['streamer'] .. 'mp4:' .. v['url']
95 else
96 s = v['url']
97 end
99 local t = S.stream_new(s)
101 t.video = {
102 bitrate_kbit_s = v['bitrate'],
103 width = v['width'],
104 height = v['height']
107 -- Save the property values that may be used later, these depend
108 -- on the language setting. Many of these are the so called
109 -- "optional media properties". The 'nostd' dictionary is used
110 -- only by this script. libquvi ignores it completely.
112 t.nostd = {
113 quality = v['quality'],
114 -- versionProg is an ID corresponding to the video language.
115 -- versionProg == 1 -> default language version, matching the video URL
116 -- language
117 -- versionProg == 2 -> alternate language version
118 -- versionProg == 3 -> original version with default language subtitles
119 -- versionProg == 8 -> default language version with subtitle for
120 -- hard-of-hearing
121 versionProg = tonumber(v['versionProg']),
122 versionCode = v['versionCode'],
123 mediaType = v['mediaType']
125 t.id = Arte.to_id(t)
127 table.insert(r, t)
130 if #r >1 then
131 Arte.ch_best(S, r)
134 return r
137 function Arte.ch_best(S, t, l)
138 local r = t[1]
139 r.flags.best = true
140 for _,v in pairs(t) do
141 if Arte.is_best_stream(v, r) then
142 r = S.swap_best(r, v)
147 function Arte.has_expired(e)
148 local d, mo, y, h, m, sc = e:match('(%d+)/(%d+)/(%d+) (%d+):(%d+):(%d+)')
150 local t = os.time({ year = y, month = mo, day = d,
151 hour = h, min = m, sec = sc })
153 return (t - os.time()) < 0
156 -- Return an ID for a stream.
157 function Arte.to_id(t)
158 -- Streaming protocol
159 local s = (t.nostd.mediaType == '') and 'http' or t.nostd.mediaType
161 return string.format("%s_%s_%s", t.nostd.quality, s, t.nostd.versionCode)
162 :gsub('%s?%-%s?', '_')
165 -- Check which stream of two is the "best".
166 function Arte.is_best_stream(v1, v2)
167 -- Select stream in default language version rather than in alternate.
168 if v2.nostd.versionProg == 2
169 and v1.nostd.versionProg ~= 2 then
170 return true
173 -- Select stream in default language version rather than in original
174 -- version/with subtitles for hard-of-hearing.
175 if v1.nostd.versionProg < v2.nostd.versionProg then
176 return true
179 return v1.video.height > v2.video.height
180 or (v1.video.height == v2.video.height
181 and v1.video.bitrate_kbit_s > v2.video.bitrate_kbit_s)
184 -- vim: set ts=2 sw=2 tw=72 expandtab: