playlist/: Change license header
[libquvi-scripts.git] / share / playlist / youtube.lua
blob5059cf6555de45be9dbac240df41b4069bce66cf
1 -- libquvi-scripts
2 -- Copyright (C) 2012 Toni Gundogdu <legatvs@gmail.com>
3 --
4 -- This file is part of libquvi-scripts <http://quvi.sourceforge.net/>.
5 --
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.
24 function ident(qargs)
25 return {
26 domains = table.concat({'youtube.com'}, ','),
27 can_parse_url = YouTube.can_parse_url(qargs)
29 end
31 -- Parse playlist properties.
32 function parse(qargs)
34 qargs.id = qargs.input_url:match('list=(%w+)')
35 while #qargs.id > 16 do -- Strip playlist ID prefix (e.g. "PL")
36 qargs.id = qargs.id:gsub("^%w", "")
37 end
38 if #qargs.id < 16 then
39 error('no match: playlist ID')
40 end
42 local Y = require 'quvi/youtube'
43 local P = require 'lxp.lom'
45 local max_results = 25
46 local start_index = 1
48 qargs.media = {}
50 local C = require 'quvi/const'
51 local o = { [C.qfo_type] = C.qft_playlist }
53 local r = {}
55 -- TODO: Return playlist thumbnail URL
56 -- TODO: Return playlist title
58 repeat -- Get the entire playlist.
59 local u = YouTube.config_url(qargs, start_index, max_results)
60 local c = quvi.fetch(u, o)
61 local x = P.parse(c)
63 YouTube.chk_error_resp(x)
64 r = YouTube.parse_media_urls(x)
66 for _,u in pairs(r) do
67 local t = {
68 url = u
70 table.insert(qargs.media, t)
71 end
73 start_index = start_index + #r
74 until #r == 0
76 return qargs
77 end
80 -- Utility functions
83 function YouTube.can_parse_url(qargs)
84 local U = require 'socket.url'
85 local t = U.parse(qargs.input_url)
86 if t and t.scheme and t.scheme:lower():match('^https?$')
87 and t.host and t.host:lower():match('youtube%.com$')
88 and t.query and t.query:lower():match('list=%w+')
89 then
90 return true
91 else
92 return false
93 end
94 end
96 function YouTube.config_url(qargs, start_index, max_results)
97 return string.format( -- Refer to http://is.gd/0msY8X
98 'http://gdata.youtube.com/feeds/api/playlists/%s?v=2'
99 .. '&start-index=%s&max-results=%s&strict=true',
100 qargs.id, start_index, max_results)
103 function YouTube.parse_media_urls(t)
104 -- TODO: Return media duration_ms
105 -- TODO: Return media title
106 local r = {}
107 if not t then return r end
108 for i=1, #t do
109 if t[i].tag == 'entry' then
110 for j=1, #t[i] do
111 if t[i][j].tag == 'link' then
112 if t[i][j].attr['rel'] == 'alternate' then
113 table.insert(r, t[i][j].attr['href'])
119 return r
122 function YouTube.chk_error_resp(t)
123 if not t then return end
124 local r = {}
125 for i=1, #t do
126 if t[i].tag == 'error' then
127 for j=1, #t[i] do
128 if t[i][j].tag == 'domain' then
129 r.domain = t[i][j][1]
131 if t[i][j].tag == 'code' then
132 r.code = t[i][j][1]
134 if t[i][j].tag == 'internalReason' then
135 r.reason = t[i][j][1]
137 if t[i][j].tag == 'location' then -- Ignores 'type' attribute.
138 r.location = t[i][j][1]
143 if #r >0 then
144 local m
145 for k,v in pairs(r) do
146 m = m .. string.format("%s=%s ", k,v)
148 error(m)
152 -- vim: set ts=2 sw=2 tw=72 expandtab: