Rename ard.lua to ardmediathek.lua
[libquvi-scripts.git] / share / lua / website / ardmediathek.lua
blob8b68a357cfdee48d27948430b23f754017a1491b
1 -- libquvi-scripts
2 -- Copyright (C) 2013 Thomas Weißschuh
3 --
4 -- This file is part of libquvi-scripts <http://quvi.sourceforge.net/>.
5 --
6 -- This library is free software; you can redistribute it and/or
7 -- modify it under the terms of the GNU Lesser General Public
8 -- License as published by the Free Software Foundation; either
9 -- version 2.1 of the License, or (at your option) any later version.
11 -- This library is distributed in the hope that it will be useful,
12 -- but WITHOUT ANY WARRANTY; without even the implied warranty of
13 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 -- Lesser General Public License for more details.
16 -- You should have received a copy of the GNU Lesser General Public
17 -- License along with this library; if not, write to the Free Software
18 -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 -- 02110-1301 USA
21 local ArdMediathek = {}
23 function ident(self)
24 package.path = self.script_dir .. '/?.lua'
25 local C = require 'quvi/const'
26 local U = require 'quvi/util'
27 local B = require 'quvi/bit'
28 local r = {}
29 r.domain = 'www%.ardmediathek%.de'
30 r.formats = 'default|best'
31 r.categories = B.bit_or(C.proto_http, C.proto_rtmp)
32 r.handles = U.handles(self.page_url, {r.domain},
33 nil, {"documentId=%d+$"})
34 return r
35 end
37 function query_formats(self)
38 local config = ArdMediathek.get_config(self)
39 local formats = ArdMediathek.iter_formats(config)
41 local t = {}
42 for _,v in pairs(formats) do
43 table.insert(t, ArdMediathek.to_s(v))
44 end
46 table.sort(t)
47 self.formats = table.concat(t, "|")
49 return self
50 end
52 function parse(self)
54 local config = ArdMediathek.get_config(self)
55 local Util = require 'quvi/util'
57 self.host_id = 'ard'
58 self.title = config:match(
59 '<meta property="og:title" content="([^"]*)'
60 ):gsub(
61 '%s*%- %w-$', '' -- remove name of station
62 ):gsub(
63 '%s*%(FSK.*', '' -- remove FSK nonsense
65 or error('no match: media title')
66 self.thumbnail_url = config:match(
67 '<meta property="og:image" content="([^"]*)'
68 ) or ''
70 local formats = ArdMediathek.iter_formats(config)
71 local format = Util.choose_format(self,
72 formats,
73 ArdMediathek.choose_best,
74 ArdMediathek.choose_default,
75 ArdMediathek.to_s)
76 or error('unable to choose format')
78 if not format.url then error('no match: media url') end
79 self.url = { format.url }
81 return self
82 end
84 function ArdMediathek.test_availability(page)
85 -- some videos are only scrapable at certain times
86 local fsk_pattern =
87 'Der Clip ist deshalb nur von (%d%d?) bis (%d%d?) Uhr verfügbar'
88 local from, to = page:match(fsk_pattern)
89 if from and to then
90 error('video only available from ' ..from.. ':00 to '
91 ..to.. ':00 CET')
92 end
93 end
95 function ArdMediathek.get_config(self)
96 local c = quvi.fetch(self.page_url)
97 self.id = self.page_url:match('documentId=(%d*)')
98 or error('no match: media id')
99 if c:match('<title>ARD Mediathek %- Fehlerseite</title>') then
100 error('invalid URL, maybe the media is no longer available')
103 return c
106 function ArdMediathek.choose_best(t)
107 return t[#t] -- return the last from the array
110 function ArdMediathek.choose_default(t)
111 return t[1] -- return the first from the array
114 function ArdMediathek.to_s(t)
115 return string.format("%s_%s_i%02d%s%s",
116 (t.quality) and t.quality or 'sd',
117 t.container, t.stream_id,
118 (t.encoding) and '_'..t.encoding or '',
119 (t.height) and '_'..t.height or '')
122 function ArdMediathek.quality_from(suffix)
123 local q = suffix:match('%.web(%w)%.') or suffix:match('%.(%w)%.')
124 or suffix:match('[=%.]Web%-(%w)') -- .webs. or Web-S or .s
125 if q then
126 q = q:lower()
127 local t = {s='ld', m='md', l='sd', xl='hd'}
128 for k,v in pairs(t) do
129 if q == k then return v end
132 return q
135 function ArdMediathek.height_from(suffix)
136 local h = suffix:match('_%d+x(%d+)[_%.]')
137 if h then return h..'p' end
140 function ArdMediathek.container_from(suffix)
141 return suffix:match('^(...):') or suffix:match('%.(...)$') or 'mp4'
144 function ArdMediathek.iter_formats(page)
145 local r = {}
146 local s = 'mediaCollection%.addMediaStream'
147 .. '%(0, (%d+), "(.-)", "(.-)", "%w+"%);'
149 ArdMediathek.test_availability(page)
151 for s_id, prefix, suffix in page:gmatch(s) do
152 local u = prefix .. suffix
153 u = u:match('^(.-)?') or u -- remove querystring
154 local t = {
155 container = ArdMediathek.container_from(suffix),
156 encoding = suffix:match('%.(h264)%.'),
157 quality = ArdMediathek.quality_from(suffix),
158 height = ArdMediathek.height_from(suffix),
159 stream_id = s_id, -- internally (by service) used stream ID
160 url = u
162 table.insert(r,t)
164 if #r == 0 then error('no media urls found') end
165 return r
168 -- vim: set ts=4 sw=4 sts=4 tw=72 expandtab: