FIX: quvi/youtube: ident: query: "v=" may not be first param
[libquvi-scripts.git] / share / common / quvi / youtube.lua
blob1248d6d34b5b50b66756f22a5d7a6050506e1bc2
1 -- libquvi-scripts
2 -- Copyright (C) 2012-2013 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 M = {}
23 --[[
24 Return the `ident' data for the {media,subtitle} scripts.
25 Parameters:
26 qargs .. quvi args
27 Returns:
28 A table containing the values expected by the library.
29 ]]--
30 function M.ident(qargs)
31 local u = M.normalize(qargs.input_url)
32 return {
33 domains = table.concat({'youtube.com'}, ','),
34 can_parse_url = M.can_parse_url(u)
36 end
38 --[[
39 Check if script can parse the URL.
40 Parameters:
41 url .. URL to check
42 Returns:
43 A boolean value.
44 ]]--
45 function M.can_parse_url(url)
46 local U = require 'socket.url'
47 local t = U.parse(url)
48 if t and t.scheme and t.scheme:lower():match('^https?$')
49 and t.host and t.host:lower():match('youtube%.com$')
50 and t.query and t.query:lower():match('v=[%w-_]+')
51 and t.path and t.path:lower():match('^/watch$')
52 then
53 return true
54 else
55 return false
56 end
57 end
59 --[[
60 "Normalize" URL to YouTube media URL. See the test URLs for examples.
61 Parameters:
62 s .. URL to normalize
63 Returns:
64 Normalized URL
65 ]]--
66 function M.normalize(url)
67 -- Leave if url is undefined for some reason.
68 if not url then
69 return url
70 end
71 local U = require 'socket.url'
72 local u = U.parse(url)
73 -- Leave if parsing fails for some reason.
74 if not u.host or not u.path then
75 return url
76 end
77 -- Unroll youtu.be
78 u.host = u.host:gsub('youtu%.be', 'youtube.com')
79 -- Process URLs with the youtube domain name only.
80 if not u.host:match('youtube%.com$') then
81 return url
82 end
83 -- Try to lookup the video/media ID.
84 for _,p in pairs({'/embed/([-_%w]+)', '/%w/([-_%w]+)', '/([-_%w]+)'}) do
85 local v_id = u.path:match(p)
86 if v_id and #v_id ==11 then -- Convert the URL into a YouTube media URL.
87 u.query = table.concat({'v=',v_id})
88 u.path = '/watch'
89 end
90 end
91 return U.build(u) -- Rebuild and return the media URL.
92 end
94 --[[
95 Append URL to qargs.media_url if it is unique by comparing video IDs.
96 Parameters:
97 url .. URL to append
98 ]]--
99 function M.append_if_unique(qargs, url)
100 if not url then return end
102 url = M.normalize(url)
104 local U = require 'socket.url'
105 local t = U.parse(url)
107 if not t.host or not t.query then return end
109 local p = 'v=([%w-_]+)'
110 local v = t.query:match(p)
112 for _,u in pairs(qargs.media_url) do
113 local tt = U.parse(u)
114 if tt.query and v == tt.query:match(p) then
115 return -- Found duplicate. Ignore URL.
119 table.insert(qargs.media_url, url)
123 -- Tests
126 --[[
127 local function test_normalize()
128 local test_cases = {
129 {url = 'http://youtu.be/3WSQH__H1XE',
130 expect = 'http://youtube.com/watch?v=3WSQH__H1XE'},
131 {url = 'https://youtu.be/3WSQH__H1XE',
132 expect = 'https://youtube.com/watch?v=3WSQH__H1XE'},
133 {url='http://youtu.be/v/3WSQH__H1XE?hl=en',
134 expect='http://youtube.com/watch?v=3WSQH__H1XE'},
135 {url='http://youtu.be/watch?v=3WSQH__H1XE',
136 expect='http://youtube.com/watch?v=3WSQH__H1XE'},
137 {url='http://youtu.be/embed/3WSQH__H1XE',
138 expect='http://youtube.com/watch?v=3WSQH__H1XE'},
139 {url='http://youtu.be/v/3WSQH__H1XE',
140 expect='http://youtube.com/watch?v=3WSQH__H1XE'},
141 {url='http://youtu.be/e/3WSQH__H1XE',
142 expect='http://youtube.com/watch?v=3WSQH__H1XE'},
143 {url='http://youtube.com/watch?v=3WSQH__H1XE',
144 expect='http://youtube.com/watch?v=3WSQH__H1XE'},
145 {url='http://youtube.com/embed/3WSQH__H1XE',
146 expect='http://youtube.com/watch?v=3WSQH__H1XE'},
147 {url='http://jp.youtube.com/watch?v=3WSQH__H1XE',
148 expect='http://jp.youtube.com/watch?v=3WSQH__H1XE'},
149 {url='http://jp.youtube.com/embed/3WSQH__H1XE',
150 expect='http://jp.youtube.com/watch?v=3WSQH__H1XE'},
151 {url='https://jp.youtube.com/embed/3WSQH__H1XE',
152 expect='https://jp.youtube.com/watch?v=3WSQH__H1XE'},
153 {url='http://youtube.com/3WSQH__H1XE', -- invalid page url
154 expect='http://youtube.com/watch?v=3WSQH__H1XE'}
156 local i,e = 0,0
157 for _,v in pairs(test_cases) do
158 local r = M.normalize(v.url)
159 if r ~= v.expect then
160 print(string.format('input: %s (#%s)\nexpected: %s\ngot: %s',
161 v.url, i, v.expect, r))
162 e = e+1
164 i = i+1
166 print((e==0) and 'tests OK' or error('failed tests: '..e))
169 test_normalize()
170 ]]--
172 return M
174 -- vim: set ts=2 sw=2 tw=72 expandtab: