generate_hints: special case for sizeless anchor
[conkeror.git] / modules / page-modes / youtube.js
blobfb418c71f0a28efe521a47dad9f9f57711d174a5
1 /**
2  * (C) Copyright 2008 Jeremy Maitin-Shepard
3  * (C) Copyright 2009-2011 John J. Foerch
4  *
5  * Use, modification, and distribution are subject to the terms specified in the
6  * COPYING file.
7 **/
9 in_module(null);
11 require("content-buffer.js");
12 require("media.js");
14 var youtube_t_regexp = /"t": "([^"]+)"/;
15 var youtube_title_regexp = /<meta name="title" content="([^"]+)">/;
17 function regexp_exec (regexp, string, group) {
18     var res = regexp.exec(string);
19     if (! res)
20         return null;
21     return res[group];
24 function youtube_parse_video_info (info) {
25     var sp = info.split("&");
26     var res = {};
27     for each (var kv in sp) {
28         let [k, v] = kv.split("=");
29         res[k] = decodeURIComponent(v);
30     }
31     if (! res.url_encoded_fmt_stream_map) {
32         dumpln(dump_obj(res));
33         return [];
34     }
35     var url_encoded_fmt_stream_map =
36         res.url_encoded_fmt_stream_map.split(",");
37     var data = [];
38     for each (var chunk in url_encoded_fmt_stream_map) {
39         var url = "", itag = "";
40         var d = {};
41         for each (kv in chunk.split("&")) {
42             let [k, v] = kv.split("=");
43             d[k] = decodeURIComponent(v);
44         }
45         data.push(d);
46     }
47     return data;
50 function youtube_get_video_info (url, id, t) {
51     for each (el in ["profilepage", "detailpage"]) {
52         var video_info_url =
53             "http://www.youtube.com/get_video_info?&video_id="+
54             encodeURIComponent(id)+"&el="+el+"&ps=default&eurl="+
55             encodeURIComponent(url)+"&hl=en_US&t="+encodeURIComponent(t);
56         var res = yield send_http_request({uri: video_info_url});
57         if (res) {
58             var info = youtube_parse_video_info(res.responseText);
59             yield co_return(info);
60         }
61     }
64 function youtube_scrape_text (results, frame, url, id, text) {
65     var title = decodeURIComponent(regexp_exec(youtube_title_regexp, text, 1)
66                                    || "video"+Date.now());
67     var t = regexp_exec(youtube_t_regexp, text, 1);
68     if (! t)
69         yield co_return();
70     var info = yield youtube_get_video_info(url, id, t);
71     for each (var d in info) {
72         var extension = mime_service.getPrimaryExtension(
73             d.type, regexp_exec(/\/([^;]+)/, d.type, 1));
74         results.push(load_spec({
75             uri: d.url,
76             title: title,
77             filename_extension: extension,
78             source_frame: frame,
79             mime_type: d.type,
80             description: d.quality + " " + extension
81         }));
82     }
85 function youtube_scrape_buffer (buffer, results) {
86     var url = buffer.current_uri.spec;
87     var id = regexp_exec(youtube_uri_regexp, url, 1);
88     if (! id)
89         yield co_return();
90     var text = buffer.document.documentElement.innerHTML;
91     yield youtube_scrape_text(results, buffer.top_frame, url, id, text);
94 define_page_mode("youtube_mode",
95     $display_name = "YouTube",
96     $enable = function (buffer) {
97         media_setup_local_object_classes(buffer);
98     });
100 function youtube_scrape_embedded (buffer, results) {
101     const embedded_youtube_regexp = /^http:\/\/[a-zA-Z0-9\-.]+\.youtube\.com\/v\/([^?]*).*$/;
102     for (let frame in frame_iterator(buffer.top_frame, buffer.focused_frame)) {
103         // Look for embedded YouTube videos
104         let obj_els = frame.document.getElementsByTagName("object");
105         for (let i = 0; i < obj_els.length; ++i) {
106             let obj_el = obj_els[i];
107             let param_els = obj_el.getElementsByTagName("param");
108             inner:
109             for (let j = 0; j < param_els.length; ++j) {
110                 let param_el = param_els[j];
111                 let match;
112                 if (param_el.getAttribute("name").toLowerCase() == "movie" &&
113                     (match = embedded_youtube_regexp.exec(param_el.getAttribute("value"))) != null) {
114                     try {
115                         let id = match[1];
116                         let lspec = load_spec({uri: "http://youtube.com/watch?v=" + id});
117                         var result =
118                             yield buffer.window.minibuffer.wait_for(
119                                 "Requesting " + lspec.uri + "...",
120                                 send_http_request(lspec));
121                         let text = result.responseText;
122                         if (text != null && text.length > 0)
123                             yield youtube_scrape_text(results, frame, lspec.uri, id, text);
124                     } catch (e if (e instanceof abort)) {
125                         // Still allow other media scrapers to try even if the user aborted an http request,
126                         // but don't continue looking for embedded youtube videos.
127                         yield co_return();
128                     } catch (e) {
129                         // Some other error here means there was some problem with the request.
130                         // We'll just ignore it.
131                     }
132                     break inner;
133                 }
134             }
135         }
136     }
140 let youtube_uri_regexp = build_url_regex($domain = /(?:[a-z]+\.)?youtube/,
141                                          $path = /watch\?v=([A-Za-z0-9\-_]+)/);
142 media_scrapers.unshift([/.*/, youtube_scrape_embedded]);
143 media_scrapers.unshift([youtube_uri_regexp, youtube_scrape_buffer]);
144 auto_mode_list.push([youtube_uri_regexp, youtube_mode]);
146 provide("youtube");