いくつかのSNSの元画像URLを右クリックでコピーしたり表示したりなどするChrome拡張(更新)


前に作ったChrome拡張をバージョンアップしました。

右クリックからSNS上の画像/動画URLをコピーしたり、選択範囲の画像/動画の拡張子を持つURLを開いたりする拡張です。

が、ウェブページの更新によってある日使えない機能が出てきたりするのでご注意を!

Webページを見るのに不具合があった場合は、ページをリロード、もしくは拡張の削除をお勧めします。
重大なバグは報告していただけたら幸いです。
この拡張の使用による損害の責任は負いません。
転載などはご遠慮願います。

各機能に共通している点は"右クリック"からメニューを開き、クリップボードにコピーする場合ポップアップ、画像を開く場合は別タブが開く、ダウンロードはダウンロード開始などの挙動が伴います。何もおきないという場合は失敗したということです(!)

■Chrome拡張のインストール
RClickImageTools.crx ver0.3


機能別に数字を振っておきました。説明と、こんなページで使えるという例を貼っておきます。

0.リンクURLをコピー[Google検索]
"contexts": [ "link" ]
Google検索結果のリンク上で動作します。遷移先のページのURLをクリップボードにコピーします。
https://www.google.co.jp/search?q=%E3%81%98%E3%82%83%E3%82%93%E3%81%90%E3%82%8B%E3%83%AC%E3%83%87%E3%82%A3oh

1.メディアURLをコピー
"contexts": [ "image","video" ]
画像/動画の上で動作します。各メディアのURLをクリップボードにコピーします。Google+やtwitterの画像は最大サイズでコピーします。

2.メディアURLをコピー
"contexts": [ "frame" ]
twitterの動画の上で動作します。動画のURLをクリップボードにコピーします。
https://twitter.com/Rinacchi_NMB48/status/715908858330353664

3.メディアタグをコピー
"contexts": [  "image","video"  ]
画像/動画の上で動作します。各メディアのURLを<img><video>タグのHTML形式でクリップボードにコピーします。widthのデフォルト値は480pxです。

4.メディアタグをコピー
"contexts": [ "frame" ]
twitterの動画の上で動作します。動画のURLを<video>タグのHTML形式でクリップボードにコピーします。widthのデフォルト値は480pxです。
https://twitter.com/Rinacchi_NMB48/status/715908858330353664

5.メディアタグをコピー
"contexts": [  "page"  ]
任意のページ上の適当な場所で右クリックすると動作します。ページ上の各メディアのURLを<img><video>タグのHTML形式でクリップボードにコピーします。widthのデフォルト値は480pxです。
https://plus.google.com/photos/109057690948151627836/album/6270897965967077697

6.メディアをテキスト形式でコピー
"contexts": [  "page"  ]
任意のページ上の適当な場所で右クリックすると動作します。ページ上の各メディアのURLをクリップボードにコピーします。
https://plus.google.com/photos/109057690948151627836/album/6270897965967077697

7.投稿をテキスト形式でコピー
"contexts": [  "page"  ]
Google+,twitter.instagramの投稿詳細ページの適当な場所で右クリックすると動作します。SNSの投稿をテキストベースでクリップボードにコピーします。
https://twitter.com/naru3official30/status/715286051795775488

8.埋め込みタグをコピー
"contexts": [  "page"  ]
Google+,twitter.instagramの投稿詳細ページの適当な場所で右クリックすると動作します。SNSの投稿を埋め込みタグのHTML形式でクリップボードにコピーします。
https://twitter.com/naru3official30/status/715286051795775488

9.埋め込みタグをコピー
"contexts": [ "link" ]
Google+,twitter.youtubeのリンク上で動作します。SNSの投稿を埋め込みタグのHTML形式でクリップボードにコピーします。
https://www.youtube.com/results?search_query=じゃんぐるレディoh

10.別タブで開く
"contexts": [ "image","video" ]
画像/動画の上で動作します。各メディアを新しいタブで開きます。Google+やtwitterの画像は最大サイズで開きます。

11.別タブで開く
"contexts": [ "frame" ]
twitterの動画の上で動作します。動画を新しいタブで開きます。
https://twitter.com/Rinacchi_NMB48/status/715908858330353664

12.選択範囲の画像を開く
"contexts": [ "selection" ]
画像/動画の拡張子を持つURL文字列を選択し右クリックすると動作します。各メディアを新しいタブで開きます。Google+やtwitterの画像は最大サイズで開きます。

http://pbs.twimg.com/media/CfUdGTbUUAIZNwi.jpg:orig
https://pbs.twimg.com/media/CfA0qk8UIAE5X_f.jpg
http://lh3.googleusercontent.com/-bB9g8Zh9MZU/VERSgjb054I/AAAAAAAHqAw/rVXZ6vePC08/s0/photo.jpg
↑範囲選択→右クリック

13.選択範囲の画像をタグにしてコピー
"contexts": [ "selection" ]
選択範囲に画像/動画の拡張子を持つURLがあると動作します。各メディアのURLを<img><video>タグのHTML形式でクリップボードにコピーします。widthのデフォルト値は480pxです。
http://pbs.twimg.com/media/CfUdGTbUUAIZNwi.jpg:orig
https://pbs.twimg.com/media/CfA0qk8UIAE5X_f.jpg
http://lh3.googleusercontent.com/-bB9g8Zh9MZU/VERSgjb054I/AAAAAAAHqAw/rVXZ6vePC08/s0/photo.jpg
↑範囲選択→右クリック

14.Downloadする
"contexts": [ "image","video" ]
画像/動画の上で動作します。各メディアをダウンロードします。Google+やtwitterの画像は最大サイズでダウンロードします。

15.Downloadする
"contexts": [ "frame" ]
twitter動画の上で動作します。動画をダウンロードします。
https://twitter.com/Rinacchi_NMB48/status/715908858330353664

16.Downloadする
"contexts": [ "selection" ]
選択範囲に画像/動画の拡張子を持つURLがあると動作します。各メディアをダウンロードします。Google+やtwitterの画像は最大サイズでダウンロードします。
http://pbs.twimg.com/media/CfUdGTbUUAIZNwi.jpg:orig
https://pbs.twimg.com/media/CfA0qk8UIAE5X_f.jpg
http://lh3.googleusercontent.com/-bB9g8Zh9MZU/VERSgjb054I/AAAAAAAHqAw/rVXZ6vePC08/s0/photo.jpg
↑範囲選択→右クリック



↓↓↓以下は古い記事です↓↓↓

Google+、twitter、amblo、instagramとSNSみるようになりまして、画像などメディア蟻の数ほどあるけれども、画像がリサイズされた状態になっていることが殆どで、元画像が見たいと思ってもサイトごとにURLの仕組みが違い面倒、右クリックが禁止されてたりする、ということで閲覧用に右クリックで使えるchrome拡張を作ってみました!
Webページを見るのに不具合があった場合は、ページをリロード、もしくは拡張の削除をお勧めします。
・右クリックすると項目が表示されるがクリックしても何も起きない
・どういうシチュエーションで使えるかわかりにくい
など問題点は多いと思います。バグもあると思います。
重大なバグは報告していただけたら幸いです。

■拡張のインストール
RClickImageTools.crx

アップデートの予定はとりあえずありません。今はNMBが使ってるSNS中心の設計です。
機能は以下の通りです。⑦のその他はあったら便利そうな機能です。


①画像のフルサイズURLを開く(Google+,twitter,ameblo,instagram 対応)

 画像の上で右クリックから選択。新しいタブで開きます。
 ※ambeblo,instagramは初期設定で右クリックが無効化されています。

②画像のフルサイズURLをコピー(Google+,twitter,ameblo,instagram 対応)

 画像の上で右クリックから選択。確認ダイアログの表示があります。
 ※ambeblo,instagramは初期設定で右クリックが無効化されています。


③ 動画URLをクリップボードにコピー(twitter 対応)

 twitter上で使えます。『⑤動画の埋め込みタグを・・・』も参照してください。

④埋め込みタグをクリップボードにコピー(Google+,twitter,Youtube 対応)
 
 投稿リンクの上で右クリックから選択。確認ダイアログの表示があります。
 こんな感じのシンプルなタグです↓
Google+
<script type='text/javascript' src='https://apis.google.com/js/plusone.js'></script><div class='g-post' data-href='https://plus.google.com/u/0/103350333579457321452/posts/5nUbvUFnWSK'></div> 
twitter
<blockquote class='twitter-tweet' lang='ja'><a href='https://twitter.com/naru3official30/status/647057415150538752'></a></blockquote><script async src='//platform.twitter.com/widgets.js' charset='utf-8'></script>
分かりにくいかもしれませんが、リンクを右クリックです。(例)


⑤動画の埋め込みタグをクリップボードにコピー(twitter,mp4 対応)
 
 動画の上で右クリックから選択。確認ダイアログの表示があります。
 こんな感じのシンプルなタグです↓
<video src='https://video.twimg.com/ext_tw_video/648010659540525056/pu/vid/474x640/zOqsNn1PgO6bRyES.mp4'/> 
twitter公式サイトで確認しました。


⑥選択した画像を開く(.jpg | .jpeg | .png | .gif | .mp4 対応)
 
 画像のURL文字列を含む範囲をカーソルで選択して選択。確認ダイアログの表示があります。
 あまり複雑な文字列だとバグると思います。
 大量に選択しすぎると大量のタブが開くので注意。
 例えばこんな文字列に有効です。(httpから始まり.jpgなどで終わるURLの羅列)
 http://i.imgur.com/aR1B4um.jpg
 http://i.imgur.com/uND35PO.jpg
 http://i.imgur.com/vXn3P8q.jpg
 
こんな風に範囲選択して右クリック。


⑦その他

 右クリックで出来たら便利そうな機能です。




参考サイト様
background.js ⇔ content.js 通信
http://tigawa.github.io/blog/2013/10/13/chrome-extensions-message/
クリップボードにコピー
http://qiita.com/ororog/items/146b7cdac85a48690c1e
ダウンロードの仕方
http://qiita.com/yaegaki/items/914ced7595f86eb00afd


ソースコード

manifest.json
{
    "name": "RClickImageTools",
    "description": "RClickImageTools",
    "version": "0.2",
    "manifest_version": 2,
    "permissions": [
        "tabs","http://*/*","https://*/*","contextMenus","clipboardRead"
    ],
    "icons":{
    "16": "icon/Untitled_Image.png"
    },
    "content_scripts": [
    {"matches": ["<all_urls>"],"js": ["src/jquery-2.1.4.min.js","src/content.js"]}
    ],
     "background": {
        "scripts": ["src/background.js"]
    }
}
background.js ※直接DOMを操作出来ない

/*************************************
クリップボードにコピー
*************************************/
chrome.contextMenus.create({
"title":"埋め込みタグをクリップボードにコピー",
"type": "normal",
    "contexts": [ "link" ],
    "onclick": function(info) {
    //alert("埋め込みタグをクリップボードにコピー link:" + info.linkUrl);
    var embed_tag;
    if(info.linkUrl.indexOf("plus.google.com")>-1&&info.linkUrl.indexOf("/posts/")>-1){
embed_tag="<script type='text/javascript' src='https://apis.google.com/js/plusone.js'></script>"
+"<div class='g-post' data-href='"+info.linkUrl+"'></div>";
}
else if(info.linkUrl.indexOf("twitter.com")>-1&&info.linkUrl.indexOf("/status/")>-1){
embed_tag="<blockquote class='twitter-tweet' lang='ja'>"
+"<a href='"+info.linkUrl+"'></a></blockquote>"
+"<script async src='//platform.twitter.com/widgets.js' charset='utf-8'></script>";
}
else if(info.linkUrl.indexOf("www.youtube.com")>-1
&&(
(info.linkUrl.indexOf("/watch")>-1&&(info.linkUrl.indexOf("?v=")>-1||info.linkUrl.indexOf("&v=")>-1))
||info.linkUrl.indexOf("/embed/")>-1
)){
var url=info.linkUrl;
if(info.linkUrl.indexOf("/watch")>-1)
url=url.substring(0,url.lastIndexOf("/"))
+"/embed/"
+url.substring(url.lastIndexOf("v=")+2,url.length);
embed_tag="<iframe width='560' height='315' src='"+url+"' frameborder='0' allowfullscreen></iframe>";
}
if(embed_tag)
clipBoard(embed_tag);
    }
});
chrome.contextMenus.create({
"title":"動画タグをクリップボードにコピー",
"type": "normal",
    "contexts": [ "frame" ],
    "onclick": function(info) {
//alert("動画タグをクリップボードにコピー frame:" + info.frameUrl);
if(info.frameUrl.indexOf("amp.twimg.com/amplify-web-player")>-1){
if(info.frameUrl.indexOf(".mp4")>-1&&info.frameUrl.indexOf("video_url=")>-1){
var url=info.frameUrl.substring(info.frameUrl.indexOf("video_url=")+"video_url=".length,info.frameUrl.indexOf(".mp4")+".mp4".length);
var embed_tag="<video src='"+url+"'/>";
clipBoard(embed_tag);
}
else{
chrome.tabs.getSelected(null, function(tab) {
chrome.tabs.sendRequest(tab.id, {greeting: "video_url"}, function(response) {
//alert("3:" + response.videoURL);
if(response.videoURL){
var embed_tag="<video src='"+response.videoURL+"'/>";
clipBoard(embed_tag);
}
});
});
}
}
}
});
chrome.contextMenus.create({
"title":"動画タグをクリップボードにコピー",
"type": "normal",
    "contexts": [ "video" ],
    "onclick": function(info) {
    //alert("動画タグをクリップボードにコピー video:" + info.srcUrl);
    var extension=info.srcUrl.match(/\.mp4/i);
if(extension!=null){
var embed_tag="<video src='"+info.srcUrl+"'/>";
clipBoard(embed_tag);
}
}
});

chrome.contextMenus.create({
"title":"メディアURLをクリップボードにコピー",
"type": "normal",
    "contexts": [ "image","video" ],
    "onclick": function(info) {
    //alert("メディアURLをクリップボードにコピー image:" + info.srcUrl);
    var fullsizeUrl;
    var url=info.srcUrl;
    var extension=url.match(/\.png|\.jpeg|\.jpg|\.gif|\.mp4/i);
    if(url.lastIndexOf("https",0)==0){
    url="http"+url.substring(5,url.length);
    }
    if(url.indexOf("googleusercontent")>-1||url.indexOf("bp.blogspot.com")>-1){ //Google+ blogger
if(url.indexOf("/proxy/")>-1){
url=url.substring(0,url.lastIndexOf("=w"));
fullsizeUrl=url+"=s0";
}
else{
url=url.substring(0,url.lastIndexOf("/",url.lastIndexOf("/")-1)+1);
fullsizeUrl=url+"s0/photo.jpg";
}
}
else if(extension!=null&&url.indexOf("pbs.twimg.com")>-1){ //twitter
if(url.indexOf(".jpg")>-1)
url=url.substring(0,url.lastIndexOf(extension))+extension+":orig";
else if(url.indexOf(".png")>-1)
url=url.substring(0,url.lastIndexOf(extension))+extension+":orig";
else if(url.indexOf(".mp4")>-1)
url=url.substring(0,url.lastIndexOf(extension))+extension;
fullsizeUrl=url;
}
else if(extension!=null&&url.indexOf("stat.ameba.jp/user_images")>-1){ //ameblo
var url1=url.substring(0,url.lastIndexOf("/")+1);
var url2=url.substring(url.lastIndexOf("_")+1,url.length);
fullsizeUrl=url1+"o"+url2;

}
else if(extension!=null&&url.indexOf("igcdn-photos-c-a.akamaihd.net")>-1){ //instagram
var url1=url.substring(0,url.lastIndexOf("/",url.lastIndexOf("/",url.lastIndexOf("/",url.lastIndexOf("/")-1)-1)-1)+1);
var url2=url.substring(url.lastIndexOf("/",url.lastIndexOf("/",url.lastIndexOf("/")-1)-1),url.length);
fullsizeUrl=url1+"s0"+url2;
}
else if(extension!=null){
fullsizeUrl=url;
}
if(fullsizeUrl)
clipBoard(fullsizeUrl);
}
});
chrome.contextMenus.create({
"title":"メディアURLをクリップボードにコピー",
"type": "normal",
    "contexts": [ "frame" ],
    "onclick": function(info) {
    //alert("メディアURLをクリップボードにコピー frame:" + info.frameUrl);
if(info.frameUrl.indexOf("amp.twimg.com/amplify-web-player")>-1){
if(info.frameUrl.indexOf(".mp4")>-1&&info.frameUrl.indexOf("video_url=")>-1){
var videoURL=info.frameUrl.substring(info.frameUrl.indexOf("video_url=")+"video_url=".length,info.frameUrl.indexOf(".mp4")+".mp4".length);
clipBoard(videoURL);
}
else{
chrome.tabs.getSelected(null, function(tab) {
chrome.tabs.sendRequest(tab.id, {greeting: "video_url"}, function(response) {
if(response.videoURL){
var videoURL=response.videoURL;
clipBoard(videoURL);
}
});
});
}
}
    }
});

function clipBoard(str){
var textArea = document.createElement("textarea");
textArea.style.cssText = "position:absolute;left:-100%";
document.body.appendChild(textArea);
textArea.value = str;
window.alert("copy:"+str);
//window.alert(textArea.value);
textArea.select();
document.execCommand("copy");
document.body.removeChild(textArea);
}

/*************************************
別タブで開く
*************************************/
chrome.contextMenus.create({
"title":"別タブで開く",
"type": "normal",
    "contexts": [ "image","video" ],
    "onclick": function(info) {
    //alert("別タブで開く image:" + info.srcUrl);
    var fullsizeUrl;
    var url=info.srcUrl;
    var extension=url.match(/\.png|\.jpeg|\.jpg|\.gif|\.mp4/i);
    if(url.lastIndexOf("https",0)==0){
    url="http"+url.substring(5,url.length);
    }
    if(url.indexOf("googleusercontent")>-1||url.indexOf("bp.blogspot.com")>-1){ //Google+ blogger
if(url.indexOf("/proxy/")>-1){
url=url.substring(0,url.lastIndexOf("=w"));
fullsizeUrl=url+"=s0";
}
else{
url=url.substring(0,url.lastIndexOf("/",url.lastIndexOf("/")-1)+1);
fullsizeUrl=url+"s0/photo.jpg";
}
}
else if(extension!=null&&url.indexOf("pbs.twimg.com")>-1){ //twitter
if(url.indexOf(".jpg")>-1)
url=url.substring(0,url.lastIndexOf(extension))+extension+":orig";
else if(url.indexOf(".png")>-1)
url=url.substring(0,url.lastIndexOf(extension))+extension+":orig";
else if(url.indexOf(".mp4")>-1)
url=url.substring(0,url.lastIndexOf(extension))+extension;
fullsizeUrl=url;
}
else if(extension!=null&&url.indexOf("stat.ameba.jp/user_images")>-1){ //ameblo
var url1=url.substring(0,url.lastIndexOf("/")+1);
var url2=url.substring(url.lastIndexOf("_")+1,url.length);
fullsizeUrl=url1+"o"+url2;

}
else if(extension!=null&&url.indexOf("igcdn-photos-c-a.akamaihd.net")>-1){ //instagram
var url1=url.substring(0,url.lastIndexOf("/",url.lastIndexOf("/",url.lastIndexOf("/",url.lastIndexOf("/")-1)-1)-1)+1);
var url2=url.substring(url.lastIndexOf("/",url.lastIndexOf("/",url.lastIndexOf("/")-1)-1),url.length);
fullsizeUrl=url1+"s0"+url2;
}
else if(extension!=null){
fullsizeUrl=url;
}
if(fullsizeUrl){
chrome.tabs.create({
"url":fullsizeUrl,
"selected": false
});
}
}
});
chrome.contextMenus.create({
"title":"別タブで開く",
"type": "normal",
    "contexts": [ "frame" ],
    "onclick": function(info) {
    //alert("別タブで開く frame:" + info.frameUrl);
if(info.frameUrl.indexOf("amp.twimg.com/amplify-web-player")>-1){
if(info.frameUrl.indexOf(".mp4")>-1&&info.frameUrl.indexOf("video_url=")>-1){
var videoURL=info.frameUrl.substring(info.frameUrl.indexOf("video_url=")+"video_url=".length,info.frameUrl.indexOf(".mp4")+".mp4".length);
chrome.tabs.create({
"url":videoURL,
"selected": false
});
}
else{
chrome.tabs.getSelected(null, function(tab) {
chrome.tabs.sendRequest(tab.id, {greeting: "video_url"}, function(response) {
if(response.videoURL){
var videoURL=response.videoURL;
chrome.tabs.create({
"url":videoURL,
"selected": false
});
}
});
});
}
}
    }
});

/*************************************
選択範囲の画像/動画を開く
*************************************/
chrome.contextMenus.create({
"title":"選択範囲の画像を開く",
"type": "normal",
    "contexts": [ "selection" ],
    "onclick": function(info) {
    //alert("選択範囲の画像を開く selection:" + info.selectionText);
    var text = info.selectionText;
    var extensions=[".png",".jpeg",".jpg",".gif",".mp4"];
    var protocols=["ttp://","ttps://"];
    //var extension=text.match(/\.png|\.jpeg|\.jpg|\.gif|\.mp4/i);
    //var protocol=text.match(/ttp:\/\/|http:\/\/|https:\/\//);
    for(var j=0;j<extensions.length;j++){
   
    //拡張子の有無を調べる
    var ext=extensions[j];
    //console.log("extension:"+ext);
    if(text.indexOf(ext)<0)
    continue;
   
    //拡張子で区切る
    var array=text.split(ext);
    for(var i=0;array.length;i++)
    {
    //console.log("array["+i+"]:"+array[i]);
    if(array[i]==null)
    break;
   
    //protocolを含まない場合除外
    var n=-1;
    for(var k=0;k<protocols.length;k++){
    if(n>-1)
    n=(array[i].lastIndexOf(protocols[k]) > n) ? array[i].lastIndexOf(protocols[k]) : n;
    else
    n=array[i].lastIndexOf(protocols[k]);
    }
    if(n<0)
    continue;
   
    var imageurl="h"+array[i].substring(n);

//ext以外の拡張子が含まれる場合除外
    var d=-1;
    for(var k=0;k<extensions.length;k++){
    d=imageurl.indexOf(extensions[k]);
    if(d>-1)
    break;
    }
    if(d>-1)
    continue;

//URL→タブを開く
imageurl+=ext;
//console.log("imageurl:"+imageurl);
chrome.tabs.create({
"url":imageurl,
"selected": false
});
}
}
}
});

content.js ※ページ上で動くので直接DOMを操作出来る。background.jsから呼び出されsendResponseで返事する。
chrome.extension.onRequest.addListener(
function(request, sender, sendResponse) {
//alert("2" + request.greeting);
if(request.greeting=="video_url"){
sendResponse({videoURL: getVideoURL()});
}
else{
sendResponse({});
}
});
function getVideoURL(){
var res;
var frames=document.getElementsByTagName("iframe");
for(var f in frames){
if(f.indexOf("xdm_")>-1&&f.indexOf("_provider")>-1)
{
var ele = document.getElementById(""+f)
var doc = ele.contentWindow.document;
var frame_ele=doc.getElementById("ExternalIframeContainer");
var value=frame_ele.getAttribute("data-player-config");
var jsonobj=JSON.parse(value);
for(var i in jsonobj.playlist){
//console.log("source:"+ jsonobj.playlist[i].source);
res=jsonobj.playlist[i].source;
break;
}
}
}
return res;
}