Skip to content

Instantly share code, notes, and snippets.

@teramako
Created July 16, 2011 04:55
Show Gist options
  • Save teramako/1086015 to your computer and use it in GitHub Desktop.
Save teramako/1086015 to your computer and use it in GitHub Desktop.
[Vimperator-plugin]Google+ Poster
var GooglePlus = null,
PostData = null;
(function init() {
if (typeof plugins.googlePlus == "undefined") {
window.setTimeout(init, 500);
} else {
GooglePlus = plugins.googlePlus;
PostData = GooglePlus.PostData;
function isLocalImage (aWindow, aImageURL) {
if (!aImageURL || aImageURL.indexOf("http") == 0)
return false;
var file = io.File(aImageURL);
if (file.exists() && file.isReadable()) {
let mime = "text/plain"
try {
mime = GooglePlus.MIME.getTypeFromFile(file);
} catch(e) {}
if (/^image\//.test(mime))
return true;
}
return false;
}
var proto = {
// override commonProto
init: function (win, imageURL) {
this.window = win;
this.file = io.File(imageURL);
if (this.file.exists() && this.file.isReadable()) {
this.uploading = true;
this.start();
} else {
throw new Error();
}
},
// override commonProto
generateData: function () {
// Picasa へのアップロード終了までスレッド待ち
while (this.uploading)
liberator.threadYield(false, true);
if (this.mediaData)
return this.mediaData;
return [];
},
get sequence () {
var s = PostData.sequence++;
return s;
},
get reqid () {
var date = new Date;
var r = date.getHours() + 3600 + date.getMinutes() + 60 + date.getSeconds() + this.sequence * 100000;
return r;
},
uploading: false,
resumableURL_BASE: "https://plus.google.com/_/upload/photos/resumable",
start: function startSession () {
var f = this.file;
var query = JSON.stringify({
protocolVersion: "0.8",
createSessionRequest: {
fields: [
{ external: { name: "file", filename: f.leafName, put: {}, size: f.fileSize } },
{ inlined: { name: "batchid", content: "" + Date.now(), contentType: "text/plain" } },
{ inlined: { name: "disable_asbe_notification", content: "true", contentType: "text/plain" } },
{ inlined: { name: "streamid", content: "updates", contentType: "text/plain" } },
{ inlined: { name: "use_upload_size_pref", content: "true", contentType: "text/plain" } }
]
}
});
var xhr = new XMLHttpRequest();
xhr.mozBackgroundRequest = true;
xhr.open("POST", this.resumableURL_BASE + "?authuser=0", true);
xhr.onload = this.upload.bind(this);
xhr.send(query);
},
upload: function (evt) {
var res = evt.target;
if (res.status != 200)
throw res.statusText;
var status = JSON.parse(res.responseText).sessionStatus;
//liberator.log(status, 0);
var URL = this.resumableURL_BASE + "?" + [
"upload_id=" + status.upload_id,
"file_id=000"
].join("&");
var stream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream);
stream.init(this.file, 0x04 | 0x08, parseInt("0644", 8), 0x04);
var mimeType = "image/jpeg";
try {
mimeType = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService).getTypeFromFile(this.file);
} catch(e) {}
var xhr = new XMLHttpRequest();
xhr.mozBackgroundRequest = true;
xhr.upload.addEventListener("progress", function (evt) {
var xhr = evt.target,
msg = "Uploading to Picasa ... ";
if (evt.lengthComputable) {
msg += Math.round(evt.loaded / evt.total * 100) + " %";
}
window.XULBrowserWindow.setJSDefaultStatus(msg);
}, false);
xhr.open("POST", URL, true);
xhr.onload = this.end.bind(this);
xhr.send(stream);
},
end: function (evt) {
var res = evt.target;
if (res.status != 200)
throw res.statusText;
window.XULBrowserWindow.setJSDefaultStatus("Done");
var status = JSON.parse(res.responseText).sessionStatus;
//liberator.log(status, 0);
var q = {
sm: JSON.stringify([this.getSMLQuery(status)]),
susp: "false",
at: GooglePlus.store.get("AT", ""),
};
var query = [key + "=" + encodeURIComponent(q[key]) for (key in q)].join("&");
var reqid = this.reqid;
var URL = "https://plus.google.com/_/sharebox/medialayout/?_reqid=" + reqid + "&rt=j";
var xhr = new XMLHttpRequest;
xhr.open("POST", URL, true);
var self = this;
xhr.onload = function () {
self.uploading = false;
};
xhr.send(query);
},
getSMLQuery: function (status) {
var d = new Array(48);
d[3] = "";
var cSI = status.additionalInfo["uploader_service.GoogleRupioAdditionalInfo"].completionInfo.customerSpecificInfo;
d[5] = [null, cSI.url, cSI.height, cSI.width];
d[9] = [];
d[21] = cSI.title;
d[24] = [null, cSI.photoPageUrl, null, cSI.mimeType, "image"];
var a = [null, cSI.url, 120, cSI.width / cSI.height * 120];
d[41] = [a, a];
d[47] = [
[null, "picasa", "http://google.com/profiles/media/provider"],
[null, "albumid=" + cSI.albumid + "&photoid=" + cSI.photoid, "http://google.com/profiles/media/onepick_media_id"]
];
return this.mediaData = d;
},
};
GooglePlus.mediaDetector.addType("picasaUploader", isLocalImage, proto);
(function (cmd) {
var imgOption = cmd.options[1];
imgOption[3] = function (context, args) {
completion.file(context, true);
return context.items;
}
})(commands.getUserCommand("googleplus"));
}
})();
// vim: sw=2 ts=2 et:
let INFO = <>
<plugin name="GooglePlusPoster" version="0.1"
summary="Post to Google+"
lang="en-US"
xmlns="http://vimperator.org/namespaces/liberator">
<author email="teramako@gmail.com">teramako</author>
<license>MPL 1.1</license>
<project name="Vimperator" minVersion="3.0"/>
<item>
<tags>:googleplus-setup</tags>
<spec>:googleplus -setup</spec>
<spec>:gp -setup</spec>
<description>
<p>Should setup at first</p>
<ol>
<li>Login to <a href="htts://plus.google.com/">Google+</a></li>
<li>Execute <ex>:googleplus -setup</ex></li>
</ol>
</description>
</item>
<item>
<tags>:googleplus-nonargs</tags>
<spec>:googleplus</spec>
<spec>:gp</spec>
<description>
<p>when argument is none, select the Google+ tab or open in new tab</p>
</description>
</item>
<item>
<tags>:googleplus :gp</tags>
<spec>:googleplus <oa>-l[link]</oa> <oa>-i[mage] <a>imageURL</a></oa> <oa>-t[o] <a>to</a></oa> <a>message</a></spec>
<spec>:gp <oa>-l[ink]</oa> <oa>-i[mage] <a>imageURL</a></oa> <oa>-t[o]> <a>to</a></oa> <a>message</a></spec>
<description>
<p>Post <a>message</a></p>
<dl>
<dt>-link</dt>
<dd>
Add the current URL. If the selections are available, add the selections as relataed page.
And when <a>-image</a> option is not specified and image elements is contained in the selections,
add the URL of the largest image.
</dd>
<dt>-image</dt>
<dd>
Specify image URL
</dd>
<dt>-to</dt>
<dd>
Specify the circles. Can set multiple. (Default: Anyone)
</dd>
</dl>
</description>
</item>
</plugin>
</>;
var HOME_URL = "https://plus.google.com/",
POST_URL_BASE = "https://plus.google.com/u/0/_/sharebox/post/";
/**
* ${RUNTIMEPATH}/info/{profileName}/googlePlus のデータ取得/保存
* @type {Object}
*/
var store = storage.newMap("googlePlus", { store: true });
// -------------------------------------------------------------------------
// Command
// ----------------------------------------------------------------------{{{
commands.addUserCommand(["gp", "googleplus"], "Google+",
function (args) {
// ----------------------
// -setup オプション
// ----------------------
if ("-setup" in args) {
setupGooglePlus();
return;
}
var message = args[0] || "",
acls = null;
// ----------------------
// -link オプション
// ----------------------
var win = null;
if ("-link" in args) {
win = content;
}
// ----------------------
// -imageURL オプション
// ----------------------
var image = null;
if ("-imageURL" in args) {
image = args["-imageURL"];
}
// ----------------------
// -to オプション
// ----------------------
if ("-to" in args && args["-to"].indexOf("anyone") == -1)
acls = [acl for ([,acl] in Iterator(store.get("CIRCLES", []))) if (args["-to"].indexOf(acl[0]) != -1)];
// 引数が何も無い場合は、Google+のページへ
if (!message && !win && !image) {
let tab = getGooglePlusTab();
if (tab)
gBrowser.mTabContainer.selectedItem = tab;
else
liberator.open(HOME_URL, { where: liberator.NEW_TAB });
return;
}
window.setTimeout(function() {
var pd = new PostData(message, win, image, acls);
postGooglePlus(pd);
}, 0);
}, {
literal: 0,
options: [
[["-link", "-l"], commands.OPTION_NOARG],
[["-imageURL", "-i"], commands.OPTION_STRING],
[["-to", "-t"], commands.OPTION_LIST, null,
function (context, args) {
let [, prefix] = context.filter.match(/^(.*,)[^,]*$/) || [];
if (prefix)
context.advance(prefix.length);
return [["anyone", "to public"]].concat([v for ([,v] in Iterator(store.get("CIRCLES", [])))]);
}],
[["-setup"], commands.OPTION_NOARG],
],
},true);
// }}}
// -------------------------------------------------------------------------
// Hint
// ----------------------------------------------------------------------{{{
hints.addMode("G", "Google+ Post",
function action(elm) {
var src = elm.src;
commandline.open("", "googleplus -i " + src + " ", modes.EX);
},
function getPath() {
return util.makeXPath(["img"]);
});
// }}}
/**
* Google+のページから必要データを保存する
* @return {Boolean}
*/
function setupGooglePlus () {
var tab = getGooglePlusTab();
if (tab) {
let data = tab.linkedBrowser.contentWindow.wrappedJSObject.OZ_initData;
if (data) {
store.set("UID", data[2][0]);
store.set("AT", data[1][15]);
let circles = data[12][0];
// CIRCLES[]: [[Name, Description, ID], ...]
store.set("CIRCLES", circles.slice(0, circles.length / 2).map(function (c) [c[1][0], c[1][2], c[0][0]]));
liberator.echomsg("Initialized: googleplus");
return true;
}
}
liberator.echoerr("Faild: initialize googleplus");
return false;
}
/**
* Google+のタブを取ってくる
* @return {Element|null}
*/
function getGooglePlusTab () {
var tabs = gBrowser.tabs;
for (let i = 0, tab; tab = tabs[i]; ++i) {
if (tab.linkedBrowser.currentURI.spec.indexOf(HOME_URL) == 0) {
return tab;
}
}
return null;
}
/**
* Post to Google+
* @param {PostData} aPostData
*/
function postGooglePlus (aPostData) {
var data = aPostData.getPostData();
var queries = [];
for (let key in data)
queries.push(key + "=" + encodeURIComponent(data[key]));
var xhr = new XMLHttpRequest();
xhr.mozBackgroundRequest = true;
xhr.open("POST", aPostData.POST_URL, true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
xhr.setRequestHeader("Origin", HOME_URL);
xhr.onreadystatechange = postGooglePlus.readyStateChange;
xhr.send(queries.join("&"));
}
/**
* Google+への送信状況を表示する
* @param {Event} aEvent
* aEvent.target は XMLHttpRequestオブジェクト
*/
postGooglePlus.readyStateChange = function GooglePlus_readyStateChange (aEvent) {
var xhr = aEvent.target,
msg = "Google+: ",
XBW = window.XULBrowserWindow;
if (xhr.readyState == 4) {
msg += (xhr.status == 200) ? "Posted" : "Post faild (" + xhr.statusText + ")";
window.setTimeout(function(XBW, msg){
if (XBW.jsDefaultStatus.indexOf("Google+:") == 0)
XBW.setJSDefaultStatus("");
}, 2000, XBW, msg);
} else {
msg += "sending...";
}
liberator.log(msg, 0);
XBW.setJSDefaultStatus(msg);
};
XPCOMUtils.defineLazyServiceGetter(this, "MIME", "@mozilla.org/mime;1", "nsIMIMEService");
/**
* Google+への送信データ生成
* @Constructor
* @param {String} aMessage
* @param {Object} aPage 現ページのコンテンツ情報
* @param {Selection} [aPage.selection] 選択オブジェクト
* @param {String} [apage.title] 現ページのタイトル
* @param {String} [aPage.url] 現ページURL
* @param {String} [aPage.image] 表示させたい画像URL
* @param {Array} aACLs ACL[]
*/
function PostData () { this.init.apply(this, arguments); }
PostData.sequence = 0;
PostData.prototype = {
init: function PD_init (aMessage, aWindow, aImageURL, aACLs) {
this.message = aMessage;
this.window = aWindow;
this.imageURL = aImageURL;
this.UID = store.get("UID", null);
liberator.assert(this.UID, "Google+ Error: UID is not set. Please login and `:googleplus -init'");
this.AT = store.get("AT", null);
liberator.assert(this.AT, "Google+ Error: AT is not set. Please login and `:googleplus -init'");
this.setACLEnties(aACLs);
},
get token () {
var t = "oz:" + this.UID + "." + this.date.getTime().toString(16) + "." + this.sequence.toString(16);
Object.defineProperty(this, "token", { value: t, });
return t;
},
get date () {
var d = new Date;
Object.defineProperty(this, "date", { value: d, });
return d;
},
get sequence () {
var s = PostData.sequence++;
Object.defineProperty(this, "sequence", { value: s });
return s;
},
get reqid () {
var r = this.date.getHours() + 3600 + this.date.getMinutes() + 60 + this.date.getSeconds() + this.sequence * 100000;
Object.defineProperty(this, "reqid", { value: r });
return r;
},
get POST_URL () {
var url = POST_URL_BASE + "?_reqid=" + this.reqid + "&rt=j";
Object.defineProperty(this, "POST_URL", { value: url });
return url
},
aclEntries: [{
scope: {
scopeType: "anyone",
name: "Anyone",
id: "anyone",
me: true,
requiresKey: false
},
role: 20,
}, {
scope: {
scopeType: "anyone",
name: "Anyone",
id: "anyone",
me: true,
requiresKey: false,
},
role: 60
}],
setACLEnties: function PD_setACLEnties (aACLs) {
if (!aACLs || aACLs.length == 0)
return this.aclEntries = Object.getPrototypeOf(this).aclEntries;
var entries = [];
for (let i = 0, len = aACLs.length; i < len; ++i) {
let acl = aACLs[i];
let scope = {
scopeType: "focusGroup",
name: acl[0],
id: this.UID + "." + acl[2],
me: false,
requiresKey: false,
groupType: "p"
};
entries.push({ scope: scope, role: 60 });
entries.push({ scope: scope, role: 20 });
}
return this.aclEntries = entries;
},
getPostData: function PD_getPostData () {
var spar = [v for each(v in this.generateSpar())];
return {
spar: JSON.stringify(spar),
at : this.AT
};
},
generateSpar: function PD_generateSpar() {
for (let i = 0, len = 17; i < len; ++i) {
switch (i) {
case 0:
yield this.message;
break;
case 1:
yield this.token;
break;
case 6:
if (!this.window && !this.imageURL) {
yield null;
} else {
var media = mediaDetector.get(this.window, this.imageURL);
var data = [JSON.stringify(media.generateData())];
if (media.hasPhoto) {
data.push(JSON.stringify(media.generateData(true)));
}
yield JSON.stringify(data);
}
break;
case 8:
yield JSON.stringify({ aclEntries: this.aclEntries });
break;
case 9:
case 11:
case 12:
yield true;
break;
case 15:
case 16:
yield false;
break;
case 10:
case 14:
yield [];
break;
default:
yield null;
break;
}
}
},
};
/**
* ノードをHTMLテキストに変換
* @param {Node} aNode
* @param {String} [aParentTag] 親ノードのタグ名
* @param {String} [aIndent] インデント文字列
* @param {Number} [aIndex] ノード番号(ol>li 時のみ使用)
* @return {String}
*/
function node2txt (aNode, aParentTag, aIndent, aIndex) {
var txt = "";
switch (aNode.nodeType) {
case Node.DOCUMENT_NODE: // 9
case Node.DOCUMENT_FRAGMENT_NODE: // 11
switch (aParentTag) {
case "ol":
case "ul":
case "dl":
aIndent = "&nbsp;&nbsp;";
break;
default:
aIndent = "";
}
txt = nodelist2txt(aNode.childNodes, aParentTag, aIndent).join("");
break;
case Node.TEXT_NODE: // 3
txt = aNode.nodeValue.replace(/\s+/g, " ");
break;
case Node.ELEMENT_NODE: // 1
let localName = aNode.localName,
children = aNode.childNodes;
switch (localName) {
case "ul":
case "ol":
case "dl":
txt = "<br/>\n" + nodelist2txt(children, localName, aIndent + "&nbsp;&nbsp;").join("");
break;
case "li":
txt = aIndent + (aParentTag == "ol" ? (" " + (aIndex+1)).slice(-2) + ". " : " * ").replace(" ", "&nbsp;", "g") +
nodelist2txt(children, "li", aIndent).join("") +
"<br/>\n";
break;
case "dt":
txt = aIndent + "<b>" + nodelist2txt(children, localName, aIndent) + "</b>:<br/>\n";
break;
case "dd":
txt = aIndent + "&nbsp;&nbsp;" + nodelist2txt(children, localName, aIndent) + "<br/>\n";
break;
case "br":
txt = "<br/>\n";
break;
case "img":
txt = "<img src=" + aNode.src.quote() + " width=\"" + aNode.width + "\" height=\"" + aNode.height + "\"/>";
break;
case "p":
txt = nodelist2txt(children, "p", "").join("") + "<br/>\n";
break;
case "a":
if (aNode.hasAttribute("href") && aNode.href.indexOf("http") == 0) {
txt = "<a href=" + aNode.href.quote() + (aNode.title ? " title=" + aNode.title.quote() : "") + ">" +
nodelist2txt(children, "a", "").join("") +
"</a>";
break;
}
default:
txt = '<' + localName + '>' +
nodelist2txt(children, localName, aIndent).join("") +
'</' + localName + '>';
}
break;
}
return txt;
}
/**
* NodeListの子をテキストにして配列で返す
* @param {NodeList} aChildNoes
* @param {String} aParentTag
* @param {String} aIndent
* @return {String[]}
*/
function nodelist2txt (aChildNodes, aParentTag, aIndent) {
var a = [], index = 0;
for (let i = 0, len = aChildNodes.length, child; child = aChildNodes[i]; ++i){
let txt = node2txt(child, aParentTag, aIndent, index);
if (txt) {
a.push(txt);
++index;
}
}
return a;
}
var mediaDetector = (function() {
var commonProto = {
init: function (win, imageURL) {
this.window = win;
this.imageURL = imageURL;
if (imageURL) {
if (win)
this.hasPhoto = true;
this.setupImage();
}
},
type: {
TITLE: 3,
MEDIA_LINK: 5,
UPLOADER: 9,
TEXT: 21,
TYPE: 24,
IMAGE: 41,
PROVIDER: 47,
},
generateData: function (isPhoto) {
var data = new Array(48);
data[this.type.TITLE] = this.getTitle(isPhoto);
data[this.type.MEDIA_LINK] = this.getMediaLink(isPhoto);
data[this.type.UPLOADER] = this.getUploader(isPhoto);
data[this.type.TEXT] = this.getContentsText(isPhoto);
data[this.type.TYPE] = this.getMediaType(isPhoto);
data[this.type.IMAGE] = this.getMediaImage(isPhoto);
data[this.type.PROVIDER] = this.getProvider(isPhoto);
return data;
},
hasPhoto: false,
imageElement: null,
setupImage: function () {
let imgs = content.document.images;
for (let i = 0, len = imgs.length, img; img = imgs[i]; ++i) {
if (img.src == this.imageURL) {
this.imageElement = img;
}
}
},
getMimeType: function (uri, defaultType) {
if (!(uri instanceof Ci.nsIURI))
uri = util.createURI(uri);
try {
return MIME.getTypeFromURI(uri);
} catch (e) {}
return defaultType;
},
getTitle: function (isPhoto) {
return (isPhoto || !this.window) ? null : this.window.document.title;
},
getContentsText: function (isPhoto) {
if (!this.window || isPhoto)
return null;
var sel = this.window.getSelection();
if (sel.isCollapsed)
return "";
var sels = [];
for (let i = 0, count = sel.rangeCount; i < count; ++i) {
let r = sel.getRangeAt(i),
fragment = r.cloneContents();
sels.push(node2txt(fragment, r.commonAncestorContainer.localName));
}
return sels.join("<br/>(snip)<br/>");
},
getUploader: function () { return []; },
getMediaLink: function (isPhoto) {
if (this.window && !isPhoto)
return [null, this.window.location.href];
var data = [null, this.imageURL];
if (this.imageElement)
data.push(this.imageElement.height, this.imageElement.width);
return data;
},
getMediaType: function (isPhoto) {
if (isPhoto) {
var type = this.getMimeType(this.imageURL, "image/jpeg");
var data = [null, this.imageURL, null, type, "photo", null,null,null,null,null,null,null];
if (this.imageElement)
data.push(this.imageElement.width, this.imageElement.height);
else
data.push(null,null);
return data;
}
if (this.window && !isPhoto) {
type = this.window.document.contentType;
switch (type.split("/")[0]) {
case "image":
return [null, this.window.location.href, null, type, "image"];
case "text":
default:
return [null, this.window.location.href, null, "text/html", "document"];
}
} else if (this.imageURL) {
type = this.getMimeType(this.imageURL, "image/jpeg");
return [null, this.imageURL, null, type, "image"];
}
return null
},
getMediaImage: function (isPhoto) {
var url;
if (this.window && !isPhoto) {
let type = this.window.document.contentType.split("/");
if (type[0] != "image") {
let host = this.window.location.host;
url = "//s2.googleusercontent.com/s2/favicons?domain=" + host;
return [ [null, url, null, null], [null, url, null, null] ];
} else {
url = this.window.location.href;
return [ [null, url, null, null], [null, url, null, null] ];
}
}
let data = [null, this.imageURL];
let w = null, h = null;
if (this.imageElement) {
w = this.imageElement.width, h = this.imageElement.height;
w = w / h * 120;
h = 120;
}
data.push(h, w);
return [ data, data ];
},
getProvider: function (isPhoto) {
return [ [null, (isPhoto ? "images" : ""), "http://google.com/profiles/media/provider"] ];
}
};
var classes = {}, checker = {};
function MediaLink() { this.init.apply(this, arguments); };
MediaLink.prototype = commonProto;
var self = {
addType: function (name, checkFunc, proto) {
checker[name] = checkFunc;
var func = function () { this.init.apply(this, arguments); };
proto.__super__ = proto.__proto__ = commonProto;
func.prototype = proto;
classes[name] = func;
},
get: function (aWindow, aImageURL) {
for (let [key, checkFunc] in Iterator(checker)) {
if (checkFunc(aWindow, aImageURL)) {
return new classes[key](aWindow, aImageURL);
}
}
return new MediaLink(aWindow, aImageURL);
}
};
(function() {
// -------------------------------------------------------------------------
// YouTube
// ----------------------------------------------------------------------{{{
self.addType("youtube",
function (win) {
if (!win) return false;
return /^https?:\/\/(?:.*\.)?youtube.com\/watch/.test(win.location.href);
}, {
get VIDEO_ID () {
var id = this.window.wrappedJSObject.yt.config_.VIDEO_ID;
Object.defineProperty(this, "VIDEO_ID", { value: id });
return id;
},
getMediaLink: function () {
return [null, "http://www.youtube.com/v/" + this.VIDEO_ID + "&hl=en&fs=1&autoplay=1"];
},
getContentsText: function () {
return this.window.document.querySelector("meta[name=description]").content;
},
getMediaType: function () [null, this.window.location.href, null, "application/x-shockwave-flash", "video"],
getMediaImage: function () {
var url = "https://ytimg.googleusercontent.com/vi/" + this.VIDEO_ID + "/hqdefault.jpg";
return [ [null, url, 120, 160], [null, url, 120, 160] ];
},
getProvider: function () [ [null, "youtube", "http://google.com/profiles/media/provider"] ],
}); // }}}
// -------------------------------------------------------------------------
// NicoNico
// ----------------------------------------------------------------------{{{
self.addType("nicovideo",
function (win) {
if (!win) return false;
var reg = /^http:\/\/www.nicovideo.jp\/watch\/sm[\d]+/;
return reg.test(win.location.href);
}, {
get VIDEO () {
var video = this.window.wrappedJSObject.Video;
Object.defineProperty(this, "VIDEO_ID", { value: video });
return video;
},
getMeidLink: function () {
return [null, "http://www.nicovideo.jp/watch/" + this.VIDEO.id];
},
getContentsText: function () {
return this.VIDEO.description;
},
getMediaType: function () {
return [null, this.window.location.href, null, "application/x-shockwave-flash", "video"];
},
getMediaImage: function () {
var url = this.VIDEO.thumbnail;
return [ [null, url, 120, 160], [ null, url, 120, 160] ];
},
getProvider: function () {
return [[null, "nicovideo", "http://google.com/profiles/media/provider"]];
}
}); // }}}
// -------------------------------------------------------------------------
// Gyazo
// ----------------------------------------------------------------------{{{
self.addType("gyazo",
function (win, image) {
var reg = /^http:\/\/gyazo\.com\/\w+(\.png)?/;
return reg.test(image);
}, {
init: function (win, imageURL) {
this.window = win;
if (imageURL.lastIndexOf(".png") != imageURL.length - 4)
imageURL += ".png";
this.imageURL = imageURL;
this.hasPhoto = true;
},
});
// }}}
})();
return self;
})();
// vim: sw=2 ts=2 et fdm=marker:
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment