2 * (C) Copyright 2008 Jeremy Maitin-Shepard
3 * (C) Copyright 2009-2011 John J. Foerch
5 * Use, modification, and distribution are subject to the terms specified in the
9 require("content-buffer.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);
22 function youtube_parse_video_info (info) {
23 var sp = info.split("&");
25 for each (var kv in sp) {
26 let [k, v] = kv.split("=");
27 res[k] = decodeURIComponent(v);
29 if (! res.url_encoded_fmt_stream_map) {
30 dumpln(dump_obj(res));
33 var url_encoded_fmt_stream_map =
34 res.url_encoded_fmt_stream_map.split(",");
36 for each (var chunk in url_encoded_fmt_stream_map) {
37 var url = "", itag = "";
39 for each (kv in chunk.split("&")) {
40 let [k, v] = kv.split("=");
41 d[k] = decodeURIComponent(v);
48 function youtube_get_video_info (url, id, t) {
49 for each (var el in ["profilepage", "detailpage"]) {
51 "http://www.youtube.com/get_video_info?&video_id="+
52 encodeURIComponent(id)+"&el="+el+"&ps=default&eurl="+
53 encodeURIComponent(url)+"&hl=en_US&t="+encodeURIComponent(t);
54 var res = yield send_http_request({uri: video_info_url});
56 var info = youtube_parse_video_info(res.responseText);
57 yield co_return(info);
62 function youtube_scrape_text (results, frame, url, id, text) {
63 var title = decodeURIComponent(regexp_exec(youtube_title_regexp, text, 1)
64 || "video"+Date.now());
65 var t = regexp_exec(youtube_t_regexp, text, 1);
68 var info = yield youtube_get_video_info(url, id, t);
69 for each (var d in info) {
70 var extension = mime_service.getPrimaryExtension(
71 d.type, regexp_exec(/\/([^;]+)/, d.type, 1));
72 results.push(load_spec({
75 filename_extension: extension,
78 description: d.quality + " " + extension
83 function youtube_scrape_buffer (buffer, results) {
84 var url = buffer.current_uri.spec;
85 var id = regexp_exec(youtube_mode_test, url, 1);
88 var text = buffer.document.documentElement.innerHTML;
89 yield youtube_scrape_text(results, buffer.top_frame, url, id, text);
92 function youtube_scrape_embedded (buffer, results) {
93 const embedded_youtube_regexp = /^http:\/\/[a-zA-Z0-9\-.]+\.youtube\.com\/v\/([^?]*).*$/;
94 for (let frame in frame_iterator(buffer.top_frame, buffer.focused_frame)) {
95 // Look for embedded YouTube videos
96 let obj_els = frame.document.getElementsByTagName("object");
97 for (let i = 0; i < obj_els.length; ++i) {
98 let obj_el = obj_els[i];
99 let param_els = obj_el.getElementsByTagName("param");
101 for (let j = 0; j < param_els.length; ++j) {
102 let param_el = param_els[j];
104 if (param_el.getAttribute("name").toLowerCase() == "movie" &&
105 (match = embedded_youtube_regexp.exec(param_el.getAttribute("value"))) != null) {
108 let lspec = load_spec({uri: "http://youtube.com/watch?v=" + id});
110 yield buffer.window.minibuffer.wait_for(
111 "Requesting " + lspec.uri + "...",
112 send_http_request(lspec));
113 let text = result.responseText;
114 if (text != null && text.length > 0)
115 yield youtube_scrape_text(results, frame, lspec.uri, id, text);
116 } catch (e if (e instanceof abort)) {
117 // Still allow other media scrapers to try even if the user aborted an http request,
118 // but don't continue looking for embedded youtube videos.
121 // Some other error here means there was some problem with the request.
122 // We'll just ignore it.
131 var youtube_mode_test =
132 build_url_regexp($domain = /(?:[a-z]+\.)?youtube/,
133 $path = /watch\?(?:.*?&)?v=([A-Za-z0-9\-_]+)/);
135 define_page_mode("youtube-mode",
137 function enable (buffer) {
138 media_setup_local_object_classes(buffer);
140 function disable (buffer) {
141 media_disable_local_object_classes(buffer);
143 $display_name = "YouTube");
145 page_mode_activate(youtube_mode);
147 media_scrapers.unshift([/.*/, youtube_scrape_embedded]);
148 media_scrapers.unshift([youtube_mode_test, youtube_scrape_buffer]);