window.js: Ensure that window_initialize_late_hook is run before other "late" hooks
[conkeror.git] / modules / page-modes / youtube.js
blob2aad607eead8b9f8e14b5315693fe04e3781a185
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 require("content-buffer.js");
10 require("media.js");
12 var youtube_t_regexp = /"t": "([^"]+)"/;
13 var youtube_title_regexp = /<meta name="title" content="([^"]+)">/;
15 function regexp_exec (regexp, string, group) {
16     var res = regexp.exec(string);
17     if (! res)
18         return null;
19     return res[group];
22 function youtube_parse_video_info (info) {
23     var sp = info.split("&");
24     var res = {};
25     for each (var kv in sp) {
26         let [k, v] = kv.split("=");
27         res[k] = decodeURIComponent(v);
28     }
29     if (! res.url_encoded_fmt_stream_map) {
30         dumpln(dump_obj(res));
31         return [];
32     }
33     var url_encoded_fmt_stream_map =
34         res.url_encoded_fmt_stream_map.split(",");
35     var data = [];
36     for each (var chunk in url_encoded_fmt_stream_map) {
37         var d = {};
38         for each (kv in chunk.split("&")) {
39             let [k, v] = kv.split("=");
40             d[k] = decodeURIComponent(v);
41         }
42         data.push(d);
43     }
44     return data;
47 function youtube_get_video_info (url, id, t) {
48     for each (var el in ["profilepage", "detailpage"]) {
49         var video_info_url =
50             "http://www.youtube.com/get_video_info?&video_id="+
51             encodeURIComponent(id)+"&el="+el+"&ps=default&eurl="+
52             encodeURIComponent(url)+"&hl=en_US&t="+encodeURIComponent(t);
53         var res = yield send_http_request({uri: video_info_url});
54         if (res) {
55             var info = youtube_parse_video_info(res.responseText);
56             yield co_return(info);
57         }
58     }
61 function youtube_scrape_text (results, frame, url, id, text) {
62     var title = decodeURIComponent(regexp_exec(youtube_title_regexp, text, 1)
63                                    || "video"+Date.now());
64     var t = regexp_exec(youtube_t_regexp, text, 1);
65     if (! t)
66         yield co_return();
67     var info = yield youtube_get_video_info(url, id, t);
68     for each (var d in info) {
69         var extension = mime_service.getPrimaryExtension(
70             d.type, regexp_exec(/\/([^;]+)/, d.type, 1));
71         results.push(load_spec({
72             uri: d.url + "&signature=" + d.sig,
73             title: title,
74             filename_extension: extension,
75             source_frame: frame,
76             mime_type: d.type,
77             description: d.quality + " " + extension
78         }));
79     }
82 function youtube_scrape_buffer (buffer, results) {
83     var url = buffer.current_uri.spec;
84     var id = regexp_exec(youtube_mode_test, url, 1);
85     if (! id)
86         yield co_return();
87     var text = buffer.document.documentElement.innerHTML;
88     yield youtube_scrape_text(results, buffer.top_frame, url, id, text);
91 function youtube_scrape_embedded (buffer, results) {
92     const embedded_youtube_regexp = /^http:\/\/[a-zA-Z0-9\-.]+\.youtube\.com\/v\/([^?]*).*$/;
93     for (let frame in frame_iterator(buffer.top_frame, buffer.focused_frame)) {
94         // Look for embedded YouTube videos
95         let obj_els = frame.document.getElementsByTagName("object");
96         for (let i = 0; i < obj_els.length; ++i) {
97             let obj_el = obj_els[i];
98             let param_els = obj_el.getElementsByTagName("param");
99             inner:
100             for (let j = 0; j < param_els.length; ++j) {
101                 let param_el = param_els[j];
102                 let match;
103                 if (param_el.getAttribute("name").toLowerCase() == "movie" &&
104                     (match = embedded_youtube_regexp.exec(param_el.getAttribute("value"))) != null) {
105                     try {
106                         let id = match[1];
107                         let lspec = load_spec({uri: "http://youtube.com/watch?v=" + id});
108                         var result =
109                             yield buffer.window.minibuffer.wait_for(
110                                 "Requesting " + lspec.uri + "...",
111                                 send_http_request(lspec));
112                         let text = result.responseText;
113                         if (text != null && text.length > 0)
114                             yield youtube_scrape_text(results, frame, lspec.uri, id, text);
115                     } catch (e if (e instanceof abort)) {
116                         // Still allow other media scrapers to try even if the user aborted an http request,
117                         // but don't continue looking for embedded youtube videos.
118                         yield co_return();
119                     } catch (e) {
120                         // Some other error here means there was some problem with the request.
121                         // We'll just ignore it.
122                     }
123                     break inner;
124                 }
125             }
126         }
127     }
130 var youtube_mode_test =
131     build_url_regexp($domain = /(?:[a-z]+\.)?youtube/,
132                      $path = /watch\?(?:.*?&)?v=([A-Za-z0-9\-_]+)/);
134 define_page_mode("youtube-mode",
135     youtube_mode_test,
136     function enable (buffer) {
137         media_setup_local_object_classes(buffer);
138     },
139     function disable (buffer) {
140         media_disable_local_object_classes(buffer);
141     },
142     $display_name = "YouTube");
144 page_mode_activate(youtube_mode);
146 media_scrapers.unshift([/.*/, youtube_scrape_embedded]);
147 media_scrapers.unshift([youtube_mode_test, youtube_scrape_buffer]);
149 provide("youtube");