Update NEWS for v0.9.20131130
[libquvi-scripts.git] / share / media / arte.lua
blobf5ce1e7ba7f9ae38ae981d8027bf449d70133bb1
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)
72 if t and t.scheme and t.scheme:lower():match('^http$')
73 and t.host and t.host:lower():match('www.arte%.tv$')
74 and t.path and t.path:lower():match('^/guide/%w+/')
75 then
76 return true
77 else
78 return false
79 end
80 end
82 function Arte.iter_streams(j)
83 local S = require 'quvi/stream'
85 local d = j['videoJsonPlayer']['VSR']
86 local r = {}
88 for _, v in pairs(d) do
90 local s = v['streamer'] -- Handle available RTMP streams.
91 and table.concat({v['streamer'], 'mp4:', v['url']})
92 or v['url']
94 local t = S.stream_new(s)
96 t.video = {
97 bitrate_kbit_s = v['bitrate'],
98 width = v['width'],
99 height = v['height']
102 -- Save the property values that may be used later, these depend
103 -- on the language setting. Many of these are the so called
104 -- "optional media properties". The 'nostd' dictionary is used
105 -- only by this script. libquvi ignores it completely.
107 t.nostd = {
108 quality = v['quality'],
109 -- versionProg is an ID corresponding to the video language.
110 -- versionProg == 1 -> default language version, matching the video URL
111 -- language
112 -- versionProg == 2 -> alternate language version
113 -- versionProg == 3 -> original version with default language subtitles
114 -- versionProg == 8 -> default language version with subtitle for
115 -- hard-of-hearing
116 versionProg = tonumber(v['versionProg']),
117 versionCode = v['versionCode'],
118 mediaType = v['mediaType']
120 t.id = Arte.to_id(t)
122 table.insert(r, t)
125 if #r >1 then
126 Arte.ch_best(S, r)
129 return r
132 function Arte.ch_best(S, t, l)
133 local r = t[1]
134 r.flags.best = true
135 for _,v in pairs(t) do
136 if Arte.is_best_stream(v, r) then
137 r = S.swap_best(r, v)
142 function Arte.has_expired(e)
143 local d, mo, y, h, m, sc = e:match('(%d+)/(%d+)/(%d+) (%d+):(%d+):(%d+)')
145 local t = os.time({ year = y, month = mo, day = d,
146 hour = h, min = m, sec = sc })
148 return (t - os.time()) < 0
151 -- Return an ID for a stream.
152 function Arte.to_id(t)
153 -- Streaming protocol
154 local s = (t.nostd.mediaType == '') and 'http' or t.nostd.mediaType
156 return string.format("%s_%s_%s", t.nostd.quality, s, t.nostd.versionCode)
157 :gsub('%s?%-%s?', '_'):lower()
160 -- Check which stream of two is the "best".
161 function Arte.is_best_stream(v1, v2)
162 -- Select stream in default language version rather than in alternate.
163 if v2.nostd.versionProg == 2
164 and v1.nostd.versionProg ~= 2 then
165 return true
168 -- Select stream in default language version rather than in original
169 -- version/with subtitles for hard-of-hearing.
170 if v1.nostd.versionProg < v2.nostd.versionProg then
171 return true
174 return v1.video.height > v2.video.height
175 or (v1.video.height == v2.video.height
176 and v1.video.bitrate_kbit_s > v2.video.bitrate_kbit_s)
179 -- vim: set ts=2 sw=2 tw=72 expandtab: