2 -- Copyright (C) 2013 Thomas Weißschuh
4 -- This file is part of libquvi-scripts <http://quvi.sourceforge.net/>.
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
21 local ArdMediathek
= {}
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'
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+$"})
37 function query_formats(self
)
38 local config
= ArdMediathek
.get_config(self
)
39 local formats
= ArdMediathek
.iter_formats(config
)
42 for _
,v
in pairs(formats
) do
43 table.insert(t
, ArdMediathek
.to_s(v
))
47 self
.formats
= table.concat(t
, "|")
54 local config
= ArdMediathek
.get_config(self
)
55 local Util
= require
'quvi/util'
58 self
.title
= config
:match(
59 '<meta property="og:title" content="([^"]*)'
61 '%s*%- %w-$', '' -- remove name of station
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="([^"]*)'
70 local formats
= ArdMediathek
.iter_formats(config
)
71 local format = Util
.choose_format(self
,
73 ArdMediathek
.choose_best
,
74 ArdMediathek
.choose_default
,
76 or error('unable to choose format')
78 if not format.url
then error('no match: media url') end
79 self
.url
= { format.url
}
84 function ArdMediathek
.test_availability(page
)
85 -- some videos are only scrapable at certain times
87 'Der Clip ist deshalb nur von (%d%d?) bis (%d%d?) Uhr verfügbar'
88 local from
, to
= page
:match(fsk_pattern
)
90 error('video only available from ' ..from
.. ':00 to '
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')
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
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
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
)
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
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
164 if #r
== 0 then error('no media urls found') end
168 -- vim: set ts=4 sw=4 sts=4 tw=72 expandtab: