2 -- Copyright (C) 2012-2013 Toni Gundogdu <legatvs@gmail.com>
4 -- This file is part of libquvi-scripts <http://quvi.sourceforge.net/>.
6 -- This program is free software: you can redistribute it and/or
7 -- modify it under the terms of the GNU Affero General Public
8 -- License as published by the Free Software Foundation, either
9 -- version 3 of the License, or (at your option) any later version.
11 -- This program 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
14 -- GNU Affero General Public License for more details.
16 -- You should have received a copy of the GNU Affero General
17 -- Public License along with this program. If not, see
18 -- <http://www.gnu.org/licenses/>.
21 local YouTube
= {} -- Utility functions unique to this script
23 -- Identify the playlist script.
26 domains
= table.concat({'youtube.com'}, ','),
27 can_parse_url
= YouTube
.can_parse_url(qargs
)
31 -- Parse playlist properties.
34 qargs
.id
= qargs
.input_url
:match('list=([%w_-]+)')
36 error('no match: playlist ID')
39 local Y
= require
'quvi/youtube'
40 local U
= require
'socket.url'
41 local L
= require
'quvi/lxph'
42 local P
= require
'lxp.lom'
44 local max_results
= 25
50 repeat -- Get the entire playlist.
51 local u
= YouTube
.config_url(qargs
, U
, start_index
, max_results
)
52 local c
= quvi
.http
.fetch(u
).data
55 YouTube
.chk_error_resp(x
)
57 YouTube
.parse_thumb_url(qargs
, L
, x
)
58 YouTube
.parse_title(qargs
, L
, x
)
60 local n
= YouTube
.parse_media_urls(qargs
, L
, x
)
61 start_index
= start_index
+ n
71 function YouTube
.can_parse_url(qargs
)
72 local U
= require
'socket.url'
73 local t
= U
.parse(qargs
.input_url
)
74 if t
and t
.scheme
and t
.scheme
:lower():match('^https?$')
75 and t
.host
and t
.host
:lower():match('youtube%.com$')
76 and t
.path
and t
.path
:lower():match('^/playlist$')
77 and t
.query
and t
.query
:lower():match('^list=[%w_-]+')
85 function YouTube
.config_url(qargs
, U
, start_index
, max_results
)
86 local u
= U
.parse(qargs
.input_url
)
87 local t
= { -- Refer to http://is.gd/0msY8X
88 u
.scheme
, '://gdata.youtube.com/feeds/api/playlists/',
89 qargs
.id
, '?v=2', '&start-index=', start_index
,
90 '&max-results=', max_results
, '&strict=true'
92 return table.concat(t
,'')
95 function YouTube
.entry_avail(x
)
97 -- app:control may contain, for example:
98 -- yt:state name='restricted' reasonCode='private'
101 if x
[i
].tag == 'app:control' then return false end
106 function YouTube
.parse_entry(qargs
, L
, x
, i
, r
)
108 if x
[i
][j
].tag == 'link' then
109 if x
[i
][j
].attr
['rel'] == 'alternate' then
111 title
= L
.find_first_tag(x
[i
], 'title')[1],
112 duration_ms
= YouTube
.parse_duration(L
, x
[i
]),
113 url
= x
[i
][j
].attr
['href']
115 table.insert(qargs
.media
, t
)
121 function YouTube
.parse_media_urls(qargs
, L
, x
)
122 if not x
then return 0 end
125 if x
[i
].tag == 'entry' then
126 if YouTube
.entry_avail(x
[i
]) then
127 YouTube
.parse_entry(qargs
, L
, x
, i
, r
)
135 function YouTube
.chk_error_resp(t
)
136 if not t
then return end
139 if t
[i
].tag == 'error' then
141 if t
[i
][j
].tag == 'domain' then
142 r
.domain
= t
[i
][j
][1]
144 if t
[i
][j
].tag == 'code' then
147 if t
[i
][j
].tag == 'internalReason' then
148 r
.reason
= t
[i
][j
][1]
150 if t
[i
][j
].tag == 'location' then -- Ignores 'type' attribute.
151 r
.location
= t
[i
][j
][1]
158 for k
,v
in pairs(r
) do
159 m
= m
.. string.format("%s=%s ", k
,v
)
165 function YouTube
.parse_title(qargs
, L
, x
)
166 if not qargs
.title
then
167 qargs
.title
= L
.find_first_tag(x
, 'title')[1]
171 function YouTube
.parse_thumb_url(qargs
, L
, x
)
172 if qargs
.thumb_url
then return end
173 local g
= L
.find_first_tag(x
, 'media:group')
175 if g
[i
].tag == 'media:thumbnail' then
176 if g
[i
].attr
['yt:name'] == 'hqdefault' then
177 qargs
.thumb_url
= g
[i
].attr
['url']
184 function YouTube
.parse_duration(L
, x
)
185 local g
= L
.find_first_tag(x
, 'media:group')
186 local d
= L
.find_first_tag(g
, 'yt:duration')
187 return tonumber(d
.attr
['seconds']) * 1000
190 -- vim: set ts=2 sw=2 tw=72 expandtab: