Thumb_on_Twitter

Add thumbnail of twitpic @twitter web site

Versión del día 19/07/2014. Echa un vistazo a la versión más reciente.

// ==UserScript==
// @id             thumb_on_twitter
// @name           Thumb_on_Twitter
// @version        2.12
// @namespace      https://greasyfork.org/scripts/2584
// @homepageURL    https://greasyfork.org/scripts/2584
// @license        https://creativecommons.org/licenses/by-nc-sa/3.0/
// @author         noi
// @description    Add thumbnail of twitpic @twitter web site
// @include        /https?:\/\/twitter.com\/.*$/
// @run-at         document-end
// @grant          GM_getValue
// @grant          GM_setValue
// @grant          GM_log
// @grant          GM_registerMenuCommand
// @grant          GM_deleteValue
// ==/UserScript==


//==============================================================
//GreaseForkがrequireの審査必要なのでいっそのこと埋め込みました。
//Copyright: JoeSimmons & Sizzlemctwizzle & IzzySoft 
//require (c)https://greasyfork.org/scripts/1884-gm-config
//==============================================================

//==============================================================
//フリー音源
//Copyright: cajo (freesound.org)
//(c)https://www.freesound.org/people/cajo/sounds/34207/
//==============================================================

//==============================================================
//Flikr用ソースコード
//Copyright:NeoCat
//http://d.hatena.ne.jp/NeoCat/20091228/1262015896
//==============================================================

//==============================================================
//サムネURL参照
//http://blog.irons.jp/2009/12/23/twitter_thumb_url/
//他
//==============================================================


/**************************************************************

WEB版ツイッターで画像のサムネ表示を追加します。
(Add thumbnail @twitter)


[概要(about)]
gif動画なのに動かなかったり、ちゃんとした拡張子で保存できなかったり、
 (gif movie not work?) (Can't save correct file extension?)
という問題を解消します。多分・・・
(This script solves problems!...Maybe...)

[対応サイト(supported)]
droplr
hatena
img.ly
imgur
instagram
Mobypicture
携帯百景movapic(一部除外excluding some patterns)
Ow.ly
photozou
twitpic
twipple
twitter(公式official pic.twitter.com)
twitter(公式official p.twimg.com)
twitter(公式official pbs.twimg.com)
yfrog


[サポート対象外(not supported)]
・flickr,tumblr
apiキーが必要なため(利用規約が第三者に開示不可) api key is required.(It's secret to any unauthorized third party.)
・携帯百景movapic
ユーザーIDを含んだURL (include UserID)(ex : http://movapic.com/UserID/pic/PageID) 


更新履歴
07/20/2014 - v2.12 add:更新通知音
07/19/2014 - v2.11 add:簡易短縮URL展開 Expand UDL(http://t.co/)
07/19/2014 - v2.10 fix:参照箇所をtitleからdata-expanded-urlに変更。読み込み失敗した画像のリロード時間をランダム変数に変更
07/11/2014 - v2.9 fix:サムネ画像の読み込み失敗でdeadlinkとなる不具合にリロード処理追加
07/06/2014 - v2.8 fix:設定画面を開いたままブラウザサイズを変更した時に最適な配置になるように変更
06/30/2014 - v2.7 add:画像がリンク切れだったらdead linkとお知らせする機能。一括でON・OFF設定する機能
06/29/2014 - v2.6 add:拡張子が画像系のURLにサムネ追加、imgurにサイズM追加
06/27/2014 - v2.5 fix:add twitter(公式official pbs.twimg.com)と、pic.twitter.comのサムネのピンボケ修正
06/27/2014 - v2.4 fix:文字修正&v2.2で追加した処理の位置ミスの修正
06/27/2014 - v2.3 fix:指摘してもらったバグの修正とか
06/26/2014 - v2.2 add:twitterが追加するサムネの表示設定追加
06/26/2014 - v2.1 fix:GreaseMonkeyでユーザー設定を取得できなかったバグ修正
06/25/2014 - v2.0 fix:大幅な構造変更と軽微なバグ修正
06/23/2014 - v1.5 fix:無駄な処理の整理
06/22/2014 - v1.4 add:imgur、携帯百景movapic、hatena、Ow.ly、Mobypicture
06/21/2014 - v1.3 add:droplr、pic.twitter.com、img.ly、photozou、p.twimg.com、twipple、yfrog
06/19/2014 - v1.2 fix:表示切り替えなどで無限に増えていくのを修正
06/18/2014 - v1.1 add:instagram
06/18/2014 - v1.0 release

***************************************************************

備忘録
ホントは短縮URLのt.coをtwitterのapiでinclude_entitiesをtrueにして
展開されたURLを取得したいけど色々面倒なので途中で放棄

Flickr
//元のURL:http://www.flickr.com/photos/ユーザー名/画像ID数値/ 
//短縮URL:http://flic.kr/p//英数字(上記画像ID数値のBase58エンコード)
//サムネhttps://yy(ファームID).staticflickr.com/サーバーID/画像ID数値_ランダム数値(ハッシュ?)_t.jpg
//元画像https://yy2.staticflickr.com/3844/画像ID数値_ランダム数値_h.jpg
//http://farm4.static.flickr.com/3342/3488883246_aa472bc65f_s.jpg
//api使わないと元URL取得は難しい
//s:75x75、t:100x100、m:240x240、指定なし(none):500x500、z:640x640、b:1024x1024、h:origin
//他にもqやnやcという指定もある。oはオリジナルだけど拡張子がjpgじゃなくてオリジナルの拡張子だから指定は難しい?


・tumblr
api必須っぽいので後回し
というかapiめんどいのでパス


・flickrについて
色々めんどくさくて後回し
http://www.flickr.com/services/rest?method=flickr.photos.getInfo&format=json&api_key=<APIキー>&photo_id=<写真ID>&jsoncallback=<コールバック関数名>
コールバック関数名は指定しないとjsonFlickrApiになる
APIキーはyahoo.comに申請しないといけない(申請しても使用する=キー公開という・・・)

取得データ
jsonFlickrApi({"photo":{"id":"3488883246", "secret":"aa472bc65f", "server":"3342", "farm":4,
                        "dateuploaded":"1241098701", "isfavorite":0, "license":"4", "rotation":0,
                        "owner":{"nsid":"34944948@N03", "username":"neo_cat", "realname":"NeoCat", "location":""},
                        "title":{"_content":"Alpaca Mix CAFE"}, ...

修正後URL:http://farm{farm-id}.static.flickr.com/{server-id}/{id}_{secret}_[画像サイズ指定].jpg

→apiキー使わない方法
  oEmbedで画像取得→枚数多いと重くなるかも
→FlickrQuickEmbedを使わせてもらう
  58エンコードされたURLは駄目。デコードしたURLを使えばいいけどユーザー名がない・・・


BASE○○のデコードは、変数 = parseInt(文字列,36);でいける?(未確認)

・facebook(短縮URLは展開しないといけないので後回し)
指定方法は2種類
https://fbcdn-sphotos-h-a.akamaihd.net/hphotos-ak-snc7/画像ID_n.jpg
https://scontent-a.xx.fbcdn.net/hphotos-xpa1/t1.0-9/q71/画像ID_o.jpg

サイズ 	アルファベット
オリジナル	o
960px		b または n または o
180px		a または q または x
130px		s
75px		t

https://scontent-a.xx.fbcdn.net/hphotos-xpa1/t1.0-9/q71/s640x640/画像ID_o.jpg
サイズ 	書き方
64px 	s64x64
80px 	s80x80
120px 	s120x120
320px 	s320x320
480px 	s480x480
640px 	s640x640
720px 	s720x720

facebookの短縮URLは2種類?
http://fb.me/
http://fb.com/



********************閉鎖? not found website******************************************
pic.im (ドキュメント)サービス終了?
    ページ: http://pic.im/<image-id>
    サムネイル画像: http://pic.im/website/thumbnail/<image-id>

picplz閉鎖?
http://picplz.com/
http://picplz.com/画像ID
http://picplz.com/user/[user-id]/pic/画像ID/
100sh(200x200)/320rh(320x320スケール)/640r(640x640スケール)

BigCanvas PhotoShare閉鎖?
//短縮URL: http://bctiny.com/p<image-noのbase36>
//ページ: http://www.bcphotoshare.com/photos/<user-id?>/<image-no>
//サムネイル画像: http://images.bcphotoshare.com/storages/<image-no>/<size>.jpg
//“thumbnail”, “large”, “thumb68″ or “thumb180″

brightkite 終了確定

**************************************************************/

/**************************追加予定****************************************************************************


Lockerz(旧Plixi, その前は TweetPhoto) (ドキュメント、アナウンス)

    ページ: http://lockerz.com/s/<photo-no>
    ページ: http://plixi.com/p/<photo-no>
    ページ: http://tweetphoto.com/<photo-no>
    サムネイル:  http://api.plixi.com/api/TPAPI.svc/imagefromurl?size=<size>&url=<ページURL>
        <size>: “thumbnail”, “small”, “mobile”, “medium” or “big”

ニコニコ動画やyoutubeの短縮URLを動画に変更

動画の拡張子の場合動画プレーヤーを埋め込み

vine.co
<iframe class="vine-embed" src="動画URL" width="320" height="320" frameborder="0"></iframe><script async src="//platform.vine.co/static/scripts/embed.js" charset="utf-8"></script>

******************************************************************************************************/



(function() {
	//定数----------------------------------------------------------------
	const fileExt = ["gif","jpg","jpeg","png","bmp"];

	//グローバル変数セット------------------------------------------------
	var cfgData = {};		//ユーザー設定画面の初期値
	var localDB = {};		//初期値(ローカルストレージに保存されるデータと同じ形式のデータベース)
	var titleDB = {};		//タイトルDB(サーバーの名称)
	var optionDB = {};		//サムネサイズ選択肢DB

	//localStorageに格納されているデータを直接確認(localDBと同じもの)
	var tmpDB = JSON.parse(localStorage.getItem("configthumbnailsize"));

	var insertWhere = "afterend";	//サムネと保存リンクの追加位置指定
	var audio = new Audio("https://www.freesound.org/data/previews/34/34207_229898-lq.mp3");	//更新通知音声

	//プログラム起動------------------------------------------------
try{
	//DB作成
	makeDB();

	//ユーザー設定画面初期値作成
	makeInitData();

	//ユーザーコンフィグ画面作成
	userCfg();

	//main起動------------------------------------------------
	document.addEventListener("DOMContentLoaded", function(evt){
		var node = evt.target;
		window.setTimeout( function() {main(node)}, 300 );
	}, false);

	//継ぎ足し要素対応
	document.addEventListener("DOMNodeInserted", function(e) {
		window.setTimeout( function() {main(e.target)}, 200 );
	}, false);

}catch(e){
	throw(e);
}

	if(localDB["alertnoticeLink"]){
		document.addEventListener('DOMAttrModified', function (e) {
			window.setTimeout( function() {chime(e.target)}, 200 );
		}, false);
		document.addEventListener("DOMNodeInserted", function(e) {
			window.setTimeout( function() {chime(e.target)}, 200 );
		}, false);
	}

	//***************************************************
	//DB入力
	function makeDB(){

		var name = "";
		var title = "";
		var def = "";		//空文字""を指定する場合注意

		//---------------------------------------------
		name = "AllThumbsAndLinks";
		title = "すべてのサムネとリンク(All Thumbs & Links)";
		def = true;

		makeServerDB(name,title,def);	//固定

		//---------------------------------------------
		name = "alertnotice";
		title = "更新通知音(alert notice by sound)";
		def = false;

		makeServerDB(name,title,def);	//固定

		//---------------------------------------------
		name = "droplr";
		title = "";
		def = "+";

		makeServerDB(name,title,def);	//固定
		optionDB[name]["-"] = "thumb:100x100(gif stop)";
		optionDB[name]["+"] = "full:original";

		//---------------------------------------------
		name = "hatena";
		title = "はてなフォトライフf.hatena";
		def = "_120";

		makeServerDB(name,title,def);	//固定
		optionDB[name]["_m"] = "_m:60x39";
		optionDB[name]["_120"] = "_120:120x77";
		optionDB[name][""] = "original";

		//---------------------------------------------
		name = "imgly";
		title = "img.ly";
		def = "thumb";

		makeServerDB(name,title,def);	//固定
		optionDB[name]["mini"] = "mini:75x75";
		optionDB[name]["thumb"] = "thumb:150x150";
		optionDB[name]["medium"] = "medium:320x240";
		optionDB[name]["large"] = "large:550x620";
		optionDB[name]["full"] = "full:original";

		//---------------------------------------------
		name = "imgur";
		title = "";
		def = "m";

		makeServerDB(name,title,def);	//固定
		optionDB[name]["s"] = "s:90x90(gif stop)";
		optionDB[name]["m"] = "m:180x320(gif stop)";
		optionDB[name]["l"] = "l:640x480(gif stop)";
		optionDB[name][""] = "original";

		//---------------------------------------------
		name = "instagram";
		title = "";
		def = "t";

		makeServerDB(name,title,def);	//固定
		optionDB[name]["t"] = "thumbnail:150x150";
		optionDB[name]["m"] = "medium:306x306";
		optionDB[name]["l"] = "large:612x612";

		//---------------------------------------------
		name = "Mobypicture";
		title = "";
		def = "thumbnail";

		makeServerDB(name,title,def);	//固定
		optionDB[name]["square"] = "thumbnail:90x90";
		optionDB[name]["thumbnail"] = "thumbnail:100x100";
		optionDB[name]["small"] = "thumbnail:500x400";
		optionDB[name]["medium"] = "medium";
		optionDB[name]["large"] = "large:original?";
		optionDB[name]["full"] = "full:original?";
		optionDB[name]["original"] = "original:original?";

		//---------------------------------------------
		name = "movapic";
		title = "携帯百景movapic";
		def = "t";

		makeServerDB(name,title,def);	//固定
		optionDB[name]["t"] = "thumbnail:150x150";
		optionDB[name]["m"] = "medium:306x306";
		optionDB[name]["l"] = "large:612x612";

		//---------------------------------------------
		name = "Owly";
		title = "Ow.ly";
		def = "thumb";

		makeServerDB(name,title,def);	//固定
		optionDB[name]["thumb"] = "thumb:100x100";
		optionDB[name]["normal"] = "normal";
		optionDB[name]["original"] = "original";

		//---------------------------------------------
		name = "photozou";
		title = "フォト蔵photozou";
		def = "thumb";

		makeServerDB(name,title,def);	//固定
		optionDB[name]["thumb"] = "thumb:120x120";
		optionDB[name]["img"] = "img:original";

		//---------------------------------------------
		name = "twipple";
		title = "ついっぷるtwipple";
		def = "thumb";

		makeServerDB(name,title,def);	//固定
		optionDB[name]["thumb"] = "thumb:160x120";
		optionDB[name]["large"] = "large:350x480";
		optionDB[name]["orig"] = "orig:original";

		//---------------------------------------------
		name = "twitpic";
		title = "";
		def = "thumb";

		makeServerDB(name,title,def);	//固定
		optionDB[name]["mini"] = "mini:75x75";
		optionDB[name]["thumb"] = "thumb:150x150";
		optionDB[name]["large"] = "large:600x800";
		optionDB[name]["full"] = "full:original";

		//---------------------------------------------
		name = "twitter1";
		title = "Official(1):pic.twitter";
		def = "thumb";

		makeServerDB(name,title,def);	//固定
		optionDB[name]["thumb"] = "thumb:150x150";
		optionDB[name]["small"] = "small:340x244";
		optionDB[name]["medium"] = "medium:600x450";
		optionDB[name]["large"] = "large:Original";

		//---------------------------------------------
		name = "twitter2";
		title = "Official(2):p.twimg";
		def = "thumb";

		makeServerDB(name,title,def);	//固定
		optionDB[name]["thumb"] = "thumb:150x150";
		optionDB[name]["small"] = "small:340x244";
		optionDB[name]["medium"] = "medium:600x450";
		optionDB[name]["large"] = "large:Original";

		//---------------------------------------------
		name = "twitter3";
		title = "Official(3):pbs.twimg.com";
		def = "thumb";

		makeServerDB(name,title,def);	//固定
		optionDB[name]["thumb"] = "thumb:150x150";
		optionDB[name]["small"] = "small:340x244";
		optionDB[name]["medium"] = "medium:600x450";
		optionDB[name]["large"] = "large:Original";

		//---------------------------------------------
		name = "yfrog";
		title = "";
		def = "small";

		makeServerDB(name,title,def);	//固定
		optionDB[name]["small"] = "small:125x90";
		optionDB[name]["iphone"] = "iphone:480x360";
		optionDB[name]["medium"] = "medium:640x480";

		//---------------------------------------------
		name = "otherPic";
		title = "その他の画像URL(Other ImageURL)";
		def = "thumb";

		makeServerDB(name,title,def);	//固定
		optionDB[name]["thumb"] = "thumb:100x100";
		optionDB[name]["origin"] = "origin:original";

	}
	//***************************************************



	//main==========================================================================================
	function main(node){

		var allLinks = document.evaluate('.//a', node, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);

		for (i = 0; i < allLinks.snapshotLength; i++){

			//短縮URLを簡易的に展開
			if(localDB["AllThumbsAndLinksSize"] && allLinks.snapshotItem(i).hasAttribute("data-expanded-url")){
				allLinks.snapshotItem(i).href = allLinks.snapshotItem(i).getAttribute("data-expanded-url");
				allLinks.snapshotItem(i).rel = "noreferrer";
			}


			//twitter公式1専用サムネ追加
			//何故か特殊で画像IDを取得するには一度短縮URLを展開しないといけない
			//手抜き対応:pic.twitter.comなら画像表示されるのでそちらのURLから拝借
			if(allLinks.snapshotItem(i).className.match("media media-thumbnail twitter-timeline-link")){

				var href = allLinks.snapshotItem(i).getAttribute("data-url");
				var src = href;

//投稿URL: http://pic.twitter.com/ページID
//画像URL: http://pbs.twimg.com/media/画像ID(ページIDではない).拡張子:サイズ
//thumb、small、medium、large(またはorig)
				//twitter公式1-------------------------------------------------------------------
				if(href.match(/^https?:\/\/pbs.twimg.com\/media\/.*$/)  && !href.match(/^https?:\/\/pbs.twimg.com\/media\/.*?\//)){
					var strSrc = "";
					var name = "twitter1";

					//「:サイズ」を削除
					href= href.replace(/(.*\/.*):.*$/i,"$1");

					src = href + ":" + localDB[name +"Size"];
					href = href + ":large";

					insertWhere = "beforebegin";	//twitter標準サムネより前に追加

					setLink(name);
					setThumb(name);

				}

			//通常のサムネ追加
			}else if(allLinks.snapshotItem(i).getAttribute("class") == "twitter-timeline-link"){

				//data-expanded-urlとhrefを含まないリンクは除外
				if(!allLinks.snapshotItem(i).hasAttribute("data-expanded-url") || !allLinks.snapshotItem(i).hasAttribute("href") 
				  || allLinks.snapshotItem(i).getAttribute("data-expanded-url") == "" || allLinks.snapshotItem(i).href == ""
				  //targetが_blankじゃなかったら除外
				  || allLinks.snapshotItem(i).getAttribute("target") != "_blank"){
					continue;
				}

				var href = allLinks.snapshotItem(i).getAttribute("data-expanded-url");
				var src = href;

				insertWhere = "afterend";

//投稿URL:http://d.pr/i/<photo_id>
//元画像:http://d.pr/<photo_id>
//元画像:http://d.pr/i/<photo_id>+
//元画像:http://d.pr/i/<photo_id>+#.jpg
//サムネ:http://d.pr/i/<photo_id>-
//サムネにするとgifは動かなくなる
//マイナス-:100x100|プラス+:ORIGIN
				//Droplr----------------------------------------------------------------------
				if(href.match(/^https?:\/\/d.pr\/i\/.*$/) && !href.match(/^https?:\/\/d.pr\/i\/.*?\//)){
					var name = "droplr";
					var picID = href.replace(/.*d.pr\/i\//,"");
					var commonUrl = "https://twitpic.com/show/";

					if(href.slice(-1) == "-" || href.slice(-1) == "+"){
						href = href.slice(0,-1);
					}
					src = href + localDB[name +"Size"];
					href = href + "+";

					setLink(name);
					setThumb(name);

//ページ: http://f.hatena.ne.jp/<user-id>/YYYYMMDD<image-id>
//サムネイル画像:http://img.f.hatena.ne.jp/images/fotolife/<user-idの1文字目>/<user-id>/YYYYMMDD/YYYYMMDD<image-id>_<size>.jpg
//_m:60x39 _120:120x77  無印:original
				//はてなフォトライフf.hatena----------------------------------------------------
				}else if(href.match(/^https?:\/\/f.hatena.ne.jp\/.*?\/.*$/) && !href.match(/^https?:\/\/f.hatena.ne.jp\/.*?\/.*?\//)){
					var name = "hatena";
					//注意:httpsは使えない
					var commonUrl = "http://img.f.hatena.ne.jp/images/fotolife/";
					var userId = href.replace(/.*f.hatena.ne.jp\/(.*?)\/.*$/i,"$1");	//ユーザーID
					var strTemp = href.replace(/.*f.hatena.ne.jp\/.*?\//,"");		//yyyymmdd画像ID
					var strTime = strTemp.slice(0,8);					//yyyymmdd

					if(strTemp != "" && !strTemp.match("fototime")){
						src = commonUrl + userId.slice(0,1) + "/" + userId + "/" + strTime + "/" + strTemp + localDB[name +"Size"] + ".jpg";
						href = commonUrl + userId.slice(0,1) + "/" + userId + "/" + strTime + "/" + strTemp + ".jpg";

						setLink(name);
						setThumb(name);
					}

//投稿URL:http://img.ly/<photo_id>
//元画像:http://img.ly/show/full/<photo_id>
//mini75x75|thumb150x150|medium320x240|large550x620|full
				//img.ly----------------------------------------------------------------------
				}else if(href.match(/^https?:\/\/img.ly\/.*$/) && !href.match(/^https?:\/\/img.ly\/.*?\//)){
					var name = "imgly";
					var picID = href.replace(/.*img.ly\//,"");
					var commonUrl = "https://img.ly/show/";

					src = commonUrl + localDB[name +"Size"] + "/" + picID;
					href = commonUrl + "full/" + picID;

					setLink(name);
					setThumb(name);

//http://i.imgur.com/画像id
//ページ: http://imgur.com/<image-id>
//ページ: http://imgur.com/<image-id>.拡張子
//サムネイル画像: http://i.imgur.com/<image-id><size>.拡張子
//s(サムネ、gif動かない90x90) l(サムネ、gif動かない640x480)  "無印"(オリジナル、gif動く) 
				//imgur--------------------------------------------------------------------------
				}else if(href.match(/^https?:\/\/(i.)?imgur.com\/.*$/) && !href.match(/^https?:\/\/(i.)?imgur.com\/.*?\//)){
					var name = "imgur";
					var commonUrl = href.replace(/^https?/,"https").replace("/imgur.com","/i.imgur.com");

					var fileType = "";	//拡張子
					fileType = href.replace(/.*imgur.com\/.*\.(.*$)/i,"$1");

					//拡張子なし
					if(fileType == href){
						src = commonUrl + localDB[name +"Size"] + ".gif";	//拡張子わからないのでとりあえずgif
						href = commonUrl + ".gif";			//拡張子わからないのでとりあえずgif
					//拡張子あり
					}else{
						src = commonUrl.replace("." + fileType, localDB[name +"Size"] + "." + fileType);
						href = commonUrl;
					}

					setLink(name);
					setThumb(name);

//http://instagr.am/p/UKCy2XOfD5/
//http://instagram.com/p/oMk34hmjwj/
//http://instagram.com/p/oMk34hmjwj/media?size=t
//sizeパラメータ t(thumbnail:150x150)、m(medium:306x306)、l(large:612x612)
				//instagram----------------------------------------------------------------------
				}else if(href.match(/^https?:\/\/instagr(am.com|.am)\/p\/.*?\//) && !href.match(/^https?:\/\/instagr(am.com|.am)\/p\/.*?\/.*\//)){
					var name = "instagram";
					var commonUrl = href.replace(/^https?/,"https").replace("instagr.am","instagram.com");

					src = commonUrl + "media?size=" + localDB[name +"Size"];
					href = commonUrl + "media?size=l";

					setLink(name);
					setThumb(name);

//ページ: http://moby.to/<image-id>
//サムネイル画像: http://moby.to/<image-id>:<size>
//“square”90x90“thumbnail”100x100, “small”500x400,  “medium” ,"large" ,"full","original"
				//Mobypicture (ドキュメント)-------------------------------------------------
				}else if(href.match(/^https?:\/\/moby.to\/.*$/) && !href.match(/^https?:\/\/moby.to\/.*?\/.*$/)){
					var name = "Mobypicture";

					src = href + ":" + localDB[name +"Size"];
					href = href + ":original";

					setLink(name);
					setThumb(name);


//ページ: http://movapic.com/pic/<image-id>
//サムネイル画像: http://image.movapic.com/pic/<size>_<image-id>.jpeg
//<size>: t(サムネ80x60)s(small320x240)m(オリジナル?)
				//携帯百景movapic--------------------------------------------------------------
				}else if(href.match(/^https?:\/\/movapic.com\/pic\/.*$/) && !href.match(/^https?:\/\/movapic.com\/pic\/.*?\/.*$/)){
					var name = "movapic";
					var picID = href.replace(/.*pic\//,"");
					var commonUrl = "http://image.movapic.com/pic/";

					src = commonUrl + localDB[name +"Size"] + "_" + picID + ".jpeg";
					href = commonUrl + "m_" + picID + ".jpeg";

					setLink(name);
					setThumb(name);

//ページ: http://ow.ly/i/<image-id>
//サムネイル画像:  http://static.ow.ly/photos/サイズ/<image-id>.jpg
//'thumb'(100x100)/'normal'/'original'
				//Ow.ly------------------------------------------------------------------------
				}else if(href.match(/^https?:\/\/ow.ly\/i\/.*$/) && !href.match(/^https?:\/\/ow.ly\/i\/.*?\/.*$/)){
					var name = "Owly";
					var picID = href.replace(/.*\/i\//,"");
					var commonUrl = "http://static.ow.ly/photos/";

					src = commonUrl + localDB[name +"Size"] + "/" + picID + ".jpg";
					href = commonUrl + "original/" + picID + ".jpg";

					setLink(name);
					setThumb(name);

//投稿URL: http://photozou.jp/photo/show/<User ID>/画像ID
//画像URL: http://photozou.jp/p/サイズ/画像ID
// thumb、img
				//フォト蔵----------------------------------------------------------------------
				}else if(href.match(/^https?:\/\/photozou.jp\/photo\/show\/.*?\/.*$/) && !href.match(/^https?:\/\/photozou.jp\/photo\/show\/.*?\/.*?\//)){
					var name = "photozou";
					var picID = href.replace(/.*\/show\/.*?\//,"");
					var commonUrl = "http://photozou.jp/p/";

					src = commonUrl + localDB[name +"Size"] + "/" + picID;
					href = commonUrl + "img/" + picID;

					setLink(name);
					setThumb(name);

//投稿URL: http://p.twipple.jp/画像ID
//画像URL: http://p.twipple.jp/show/サイズ/画像ID
//thumb、large、orig
				//ついっぷる---------------------------------------------------------------------
				}else if(href.match(/^https?:\/\/p.twipple.jp\/.*$/) && !href.match(/^https?:\/\/p.twipple.jp\/.*?\//)){
					var name = "twipple";
					var picID = href.replace(/.*twipple.jp\//,"");
					var commonUrl = "http://p.twipple.jp/show/";

					src = commonUrl + localDB[name +"Size"] + "/" + picID;
					href = commonUrl + "orig/" + picID;

					setLink(name);
					setThumb(name);

//ページ: http://twitgoo.com/<image-id>
//サムネイル画像: http://twitgoo.com/show/<size>/<image-id>
//サムネイル画像: http://twitgoo.com/<image-id>/<size>
//飛ばされる画像http://i60.twitgoo.com/画像IDじゃない文字列.jpg
//実際の画像http://i60.tinypic.com/画像IDじゃない文字列.jpg
//サムネ画像http://i60.tinypic.com/画像IDじゃない文字列_th.jpg
//“thumb”110x160, “img”オリジナル
//“mini”thumbと変わらない?
/*				//Twitgoo
				//tinypicに直さないと表示されない。しかし最初からtinypicで指定してもサムネ表示できない
				}else if(href.match(/^https?:\/\/twitgoo.com\/.*$/) && !href.match(/^https?:\/\/twitgoo.com\/.*?\//)){
					src = href + "/thumb";
					href = href + "/img";

					setLink(name);
					setThumb(name);

					//twitgooのURLをtinypicにする
//					window.setTimeout( function() {renameTwitgoo(node)}, 5000 );

*/

//http://twitpic.com/画像ID
//https://twitpic.com/show/thumb/画像ID.jpg
//mini:75x75、thumb:150x150、large:600x800、full:768x1024
				//twitpic------------------------------------------------------------------------
				}else if(href.match(/^https?:\/\/twitpic.com\//)  && !href.match(/^https?:\/\/twitpic.com\/.*?\//)){
					var name = "twitpic";
					var picID = href.replace(/.*twitpic.com\//,"");
					var commonUrl = "https://twitpic.com/show/";

					src = commonUrl + localDB[name +"Size"] + "/" + picID + ".jpg";
					href =  commonUrl + "full/" + picID + ".jpg";

					setLink(name);
					setThumb(name);

//投稿URL(何故か表示されない): http://p.twimg.com/画像ID.jpg:サイズ
//https://p.twimg.com/As2fObICEAAXRT-.jpg
//画像URL: http://pbs.twimg.com/media/画像ID.jpg:サイズ
//thumb、small、medium、large(またはorig)
				//twitter公式2-------------------------------------------------------------------
				}else if(href.match(/^https?:\/\/p.twimg.com\//)  && !href.match(/^https?:\/\/p.twimg.com\/.*?\//)){
					var name = "twitter2";
					var commonUrl = href.replace(/^https?/,"https").replace("p.twimg.com","pbs.twimg.com/media").replace(/.jpg.*$/,"");

					src = commonUrl + ".jpg:" + localDB[name +"Size"];
					href =  commonUrl + ".jpg:large";

					setLink(name);
					setThumb(name);

//http://pbs.twimg.com/media/BrHiRU5CMAE_yv-.png#twimg
				//twitter公式3
				}else if(href.match(/^https?:\/\/pbs.twimg.com\/media\/.*$/)  && !href.match(/^https?:\/\/pbs.twimg.com\/media\/.*?\//)){
					var name = "twitter3";
					var picID = href.replace(/.*twitpic.com\//,"");
					var commonUrl = href.replace(/^https?/,"https").replace(/#.*$/,"").replace(/(.*\/.*):.*$/i,"$1");

					src = commonUrl + ":" + localDB[name +"Size"];
					href = commonUrl + ":large";

					setLink(name);
					setThumb(name);

//https://vine.co/v/動画ID
//<iframe class="vine-embed" src="動画URL" width="320" height="320" frameborder="0"></iframe><script async src="//platform.vine.co/static/scripts/embed.js" charset="utf-8"></script>
/*
				//vine.co
				}else if(href.match(/^https?:\/\/vine.co\/v\/.*$/)  && !href.match(/^https?:\/\/vine.co\/v\/.*?\//)){
					var name = "vine";

					src = commonUrl + ":" + localDB[name +"Size"];
					href = commonUrl + ":large";

					setMovie(name);
*/


//http://yfrog.com/画像ID
//http://yfrog.com/画像ID:medium
//small:125x90、iphone:480x360、medium:640x480
//サムネはサイズ指定の代わりに画像IDの直後に「.th.jpg」を追加。(ただしgifは動かない)
				//yfrog--------------------------------------------------------------------------
				}else if(href.match(/^http:\/\/yfrog.com\/.*$/)  && !href.match(/^http:\/\/yfrog.com\/.*?\/.*$/)){
					var name = "yfrog";
					var commonUrl = href.replace(/^https?/,"https");

					src = commonUrl + ":" + localDB[name +"Size"];
					href =  commonUrl + ":medium";

					setLink(name);
					setThumb(name);

				//その他-------------------------------------------------------------------------
				}else{
					//拡張子ありのURLのサムネだけ追加-------------------------------------
					var comma = href.slice(-5).indexOf(".");
					var strFEx = "";		//拡張子

					if(comma > -1 && comma < 2){
						//その他の画像URLのサムネ追加
						var name = "otherPic";
						if(localDB[name + "Thumb"]){
							strFEx = href.replace(/.*\./,"");

							//画像の拡張子だったらサムネ追加
							fileExt.forEach(function(x){
								if(x == strFEx){ setThumb(name); }
							});
						}
						//動画の拡張子だったら・・・
					}
				}




			}//通常のサムネ追加ここまで
		}//for文ここまで



		//保存用のリンク追加----------------------------------------------------------------------------------
		function setLink(name){
			//ユーザー設定で追加しないなら終了
			if(localDB["AllThumbsAndLinksLink"] == false || localDB[name +"Link"] == false){
				return;
			}

			var className = '';

			if(name == "twitgoo"){
				var className = 'twitgooText';
			}

			if(allLinks.snapshotItem(i).getAttribute("ToT_Link") == undefined || allLinks.snapshotItem(i).getAttribute("ToT_Link") != "added2"){

				var ele = document.createElement("div");
				var strIcon = '<img name=imgBtn id=imgBtn type=button style=max-width:12px;display:inline-block; '
						+ 'src=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAALCAYAAACprHcmAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAABOSURBVChTjZG5DQAwCANJhs1QWZZgCSQUxHMNLs6NWSyQsq4GgY8Gx9Yb8EUjlcFfKGXgC60MrDCSAQpjGeuMZJuxlf3epfw/JpXjB4keFPsQEoUOdacAAAAASUVORK5CYII= '
						+ 'title=SaveImageAs...>';

				var strLinkText = '<a class="' + className + '" target="_blank" href="' + href + '" >' + strIcon + 'Save Image As...'
						//リンク切れ確認用imgタグ
						+ '<img src="' + src + '" onError="function reloadimg(e,timer){setTimeout( '
						//画像読み込み失敗でリロードをかける
						+ 'function(){ '
							+ 'if(e.src.match(/\\?dummy=/)){ e.src = e.src.replace(/dummy=/,\'dummy=d\');'
							+ '}else{ e.src = e.src + \'?dummy=d\' }'
						+ '},timer); }'

						//5回試行でも読み込み失敗ならdead link
						+ 'if(!this.src.match(\'dummy=ddddd\')){reloadimg(this,~~(Math.random()*(6000-2000)+2000);}else{this.parentNode.style=\'font-size:12px\';'

						+ 'this.parentNode.innerHTML=\'' + strIcon
						+ '<a href=' + allLinks.snapshotItem(i).getAttribute("data-expanded-url") + '>dead link</a>\'}"; '
						+ 'onload= "this.innerHTML=\'\';" Style="max-width:0px;max-height:0px;"></a><br>';


				//サムネを追加しない場合改行追加
				if(localDB["AllThumbsAndLinksThumb"] == false || localDB[name + "Thumb"] == false){
					allLinks.snapshotItem(i).innerHTML = "<br>" + allLinks.snapshotItem(i).innerHTML;
					strLinkText = "<br>" + strLinkText;
				}

				allLinks.snapshotItem(i).insertAdjacentHTML(insertWhere, strLinkText);

				allLinks.snapshotItem(i).setAttribute("ToT_Link","added2");
			}
		}


		//サムネ追加----------------------------------------------------------------------------------
		function setThumb(name){
			//ユーザー設定で追加しないなら終了
			if(localDB["AllThumbsAndLinksThumb"] == false || localDB[name +"Thumb"] == false){
				return;
			}

			var strMW = "400";	//max-width
			var className = "";

			//サムネのピンボケ対策などサイズ指定
			if(name == "twitter1"&& localDB[name + "Size"] == "thumb" || name == "otherPic" && localDB[name + "Size"] == "thumb"){
				strMW = "150";
			}

			if(name == "twitgoo"){
				className = 'twitgooPhoto';
			}

			if(allLinks.snapshotItem(i).getAttribute("ToT_Thumb") == undefined || allLinks.snapshotItem(i).getAttribute("ToT_Thumb") != "added"){
				var strThumbText = '<br><a class="' + className + '" target="_blank" href="' + href + '">'
					+ '<img src="' + src + '" onError="function reloadimg(e,timer){setTimeout( '
					//画像読み込み失敗でリロードをかける
					+ 'function(){ '
						+ 'if(e.src.match(/\\?dummy=/)){ e.src = e.src.replace(/dummy=/,\'dummy=d\');'
						+ '}else{ e.src = e.src + \'?dummy=d\' }'
					+ '},timer); }'

					//5回試行でも読み込み失敗ならdead link
					+ 'if(!this.src.match(\'dummy=ddddd\')){reloadimg(this,~~(Math.random()*(6000-2000)+2000));}else{this.parentNode.style=\'font-size:12px\';'

					+ 'this.insertAdjacentHTML(\'afterend\','
					+ '\'<a href=' + allLinks.snapshotItem(i).getAttribute("data-expanded-url") + '>dead link</a>'
					+ '\')}"  Style="max-width:' + strMW + 'px;"></a><br>';

				//元のリンクを改行
				allLinks.snapshotItem(i).innerHTML = "<br>" + allLinks.snapshotItem(i).innerHTML;


				allLinks.snapshotItem(i).insertAdjacentHTML(insertWhere, strThumbText);
				allLinks.snapshotItem(i).setAttribute("ToT_Thumb","added");
			}

			//twitterが追加するサムネの表示設定
			if(localDB["flgDefPic"] == false){

				//2個上の要素(コメント1個分)
				var comment = allLinks.snapshotItem(i).parentNode.parentNode;

				var allPhotos = comment.getElementsByClassName("card2 js-media-container");

				if(allPhotos[0] != undefined){
					allPhotos[0].setAttribute("ToT_del","delete");
					allPhotos[0].innerHTML = "";
				}

				if(name == "twitter1" || name == "twitter2"){
					allLinks.snapshotItem(i).innerHTML = "";
				}
			}
		}


/*
		//twitterが追加するサムネの表示設定
		if(localDB["flgDefPic"] == false){

			var allPhotos = document.evaluate('.//div[@ToT_del="delete"]', node, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);

			for (i = 0; i < allPhotos.snapshotLength; i++){
				allPhotos.snapshotItem(i).innerHTML = "";
			}
		}
*/

	}//mainここまで====================================================================================



//ユーザー設定画面(userconfig)-------------------------------------------------------------
function userCfg(){




//==============================================================
//GreaseForkがrequireの審査必要なのでいっそのこと埋め込みました。
//Copyright: JoeSimmons & Sizzlemctwizzle & IzzySoft 
//require (c)https://greasyfork.org/scripts/1884-gm-config
//==============================================================

//============================引用開始===================================

	var GM_config = {
	storage: 'GM_config',
	init: function(){
        for(var i=0,l=arguments.length,arg; i<l; ++i) {
		arg=arguments[i];
		switch(typeof arg) {
			case 'object': for(var j in arg) {
				switch(j) {
					case "open": GM_config.onOpen=arg[j]; delete arg[j]; break; // called when frame is gone
					case "close": GM_config.onClose=arg[j]; delete arg[j]; break; // called when settings have been saved
					case "save": GM_config.onSave=arg[j]; delete arg[j]; break; // store the settings objects
					default: var settings = arg;
				}
			} break;
            case 'function': GM_config.onOpen = arg; break; // passing a bare function is set to open
                        // could be custom CSS or the title string
			case 'string': if(arg.indexOf('{') !== -1 && arg.indexOf('}') !== -1) var css = arg;
				else GM_config.title = arg;
				break;
		}
	}
	if(!GM_config.title) GM_config.title = 'Settings - Anonymous Script'; // if title wasn't passed through init()

	// give the script a unique saving ID for non-firefox browsers
	GM_config.storage = GM_config.title.replace(/\W+/g, "").toLowerCase();

	var stored = GM_config.read(); // read the stored settings
	GM_config.passed_values = {};
	for(var i in settings) {
		GM_config.doSettingValue(settings, stored, i, null, false);
		if(settings[i].kids) for(var kid in settings[i].kids) GM_config.doSettingValue(settings, stored, kid, i, true);
	}
	GM_config.values = GM_config.passed_values;
	GM_config.settings = settings;
	if (css) GM_config.css.stylish = css;

 },
 open: function() {
 if(document.evaluate("//iframe[@id='GM_config']",document,null,9,null).singleNodeValue) return;
	// Create frame
	document.body.appendChild((GM_config.frame=GM_config.create('iframe',{id:'GM_config', style:'position: fixed; top: 0; left: 0; opacity: 0; display: none; z-index: 999999; width: 75%; height: 75%; max-height: 95%; max-width: 95%; border:3px ridge #000000; overflow: auto;'})));
        GM_config.frame.src = 'about:blank'; // In WebKit src cant be set until it is added to the page

	GM_config.frame.addEventListener('load', function() {
		var obj = GM_config, doc = this.contentDocument, frameBody = doc.getElementsByTagName('body')[0], create=obj.create, settings=obj.settings, anch, secNo;
		obj.frame.contentDocument.getElementsByTagName('head')[0].appendChild(create('style',{type:'text/css',textContent:obj.css.basic + "\n\n" + obj.css.stylish}));

		// Add header and title
		frameBody.appendChild(create('div', {id:'header',className:'config_header block center', innerHTML:obj.title}));

		// Append elements
		anch = frameBody; // define frame body
		secNo = 0; // anchor to append elements
		for(var i in settings) {
			var type, field = settings[i], value = obj.values[i], section = (field.section ? field.section : ["Main Options"]),
				headerExists = doc.evaluate(".//div[@class='section_header_holder' and starts-with(@id, 'section_')]", frameBody, null, 9, null).singleNodeValue;

			if(typeof field.section !== "undefined" || headerExists === null) {
				anch = frameBody.appendChild(create('div', {className:'section_header_holder', id:'section_'+secNo, kids:new Array(
				  create('a', {className:'section_header center', href:"javascript:void(0);", id:'c_section_kids_'+secNo, textContent:section[0], onclick:function(){GM_config.toggle(this.id.substring(2));}}),
				  create('div', {id:'section_kids_'+secNo, className:'section_kids', style:obj.getValue('section_kids_'+secNo, "")==""?"":"display: none;"})
				)}));
				if(section[1]) anch.appendChild(create('p', {className:'section_desc center',innerHTML:section[1]}));
				secNo++;
			}
			anch.childNodes[1].appendChild(GM_config.addToFrame(field, i, false));
		}

		// Add save and close buttons
		frameBody.appendChild(obj.create('div', {id:'buttons_holder', kids:new Array(
			obj.create('button',{id:'saveBtn',textContent:'Save',title:'Save options and close window',className:'saveclose_buttons',onclick:function(){GM_config.close(true)}}),
			obj.create('button',{id:'cancelBtn', textContent:'Cancel',title:'Close window',className:'saveclose_buttons',onclick:function(){GM_config.close(false)}}),
			obj.create('div', {className:'reset_holder block', kids:new Array(
				obj.create('a',{id:'resetLink',textContent:'Restore to default',href:'#',title:'Restore settings to default configuration',className:'reset',onclick:obj.reset})
		)}))}));

		obj.center(); // Show and center it
		window.addEventListener('resize', obj.center, false); // Center it on resize
		if (obj.onOpen) obj.onOpen(); // Call the open() callback function
		
		// Close frame on window close
		window.addEventListener('beforeunload', function(){GM_config.remove(this);}, false);
	}, false);
 },
 close: function(save) {
	if(save) {
		var type, fields = GM_config.settings, typewhite=/radio|text|hidden|password|checkbox/;
		for(f in fields) {
			var field = GM_config.frame.contentDocument.getElementById('field_'+f), kids=fields[f].kids;
			if(typewhite.test(field.type)) type=field.type;
				else type=field.tagName.toLowerCase();
			GM_config.doSave(f, field, type);
			if(kids) for(var kid in kids) {
			var field = GM_config.frame.contentDocument.getElementById('field_'+kid);
			if(typewhite.test(field.type)) type=field.type;
				else type=field.tagName.toLowerCase();
			GM_config.doSave(kid, field, type, f);
			}
		}
                if(GM_config.onSave) GM_config.onSave(); // Call the save() callback function
                GM_config.save();
	}
	if(GM_config.frame) GM_config.remove(GM_config.frame);
	delete GM_config.frame;
        if(GM_config.onClose) GM_config.onClose(); //  Call the close() callback function
 },
 set: function(name,val) {
	GM_config.values[name] = val;
 },
 get: function(name) {
	return GM_config.values[name];
 },
 isGM: (typeof window.opera === "undefined" && typeof window.chrome === "undefined" && typeof GM_info === "object" && typeof GM_registerMenuCommand === "function"),
 log: function(str) {

	if(this.isGM) return GM_log(str);
		else if(window.opera) return window.opera.postError(str);
		else return console.log(str);

 },
 getValue : function(name, d) {
	var r, def = (typeof d !== "undefined" ? d : "");
	switch(this.isGM === true) {
		case true: r = GM_getValue(name, def); break;
		case false: r = localStorage.getItem(name) || def; GM_log("test:" + typeof GM_info); break;
	}
	return r;
},
 setValue : function(name, value) {
	switch(this.isGM === true) {
		case true: GM_setValue(name, value); break;
		case false: localStorage.setItem(name, value); break;
	}
 },
  deleteValue : function(name) {
	switch(this.isGM === true) {
		case true: GM_deleteValue(name); break;
		case false: localStorage.removeItem(name); break;
	}
},
 save: function(store, obj) {
    try {
		var val = JSON.stringify(obj || GM_config.values);
		GM_config.setValue((store||GM_config.storage),val);
    } catch(e) {
		GM_config.log("GM_config failed to save settings!\n" + e);
    }
 },
 read: function(store) {
	var val = GM_config.getValue((store || GM_config.storage), '{}');
	switch(typeof val) {
		case "string": var rval = JSON.parse(val); break;
		case "object": var rval = val; break;
		default: var rval = {};
	}
    return rval;
 },
 reset: function(e) {
	e.preventDefault();
	var type, obj = GM_config, fields = obj.settings;
	for(f in fields) {
		var field = obj.frame.contentDocument.getElementById('field_'+f), kids=fields[f].kids;
		if(field.type=='radio'||field.type=='text'||field.type=='checkbox') type=field.type;
		else type=field.tagName.toLowerCase();
		GM_config.doReset(field, type, null, f, null, false);
		if(kids) for(var kid in kids) {
			var field = GM_config.frame.contentDocument.getElementById('field_'+kid);
			if(field.type=='radio'||field.type=='text'||field.type=='checkbox') type=field.type;
				else type=field.tagName.toLowerCase();
			GM_config.doReset(field, type, f, kid, true);
		}
	}
 },
 addToFrame : function(field, i, k) {
	var elem, obj = this, anch = this.frame, value = obj.values[i], Options = field.options, label = field.label, create=obj.create, isKid = (k !== null && k === true);
		switch(field.type) {
				case 'textarea':
					elem = create(isKid ? "span" : "div", {title:field.title||'', kids:new Array(
						create('span', {textContent:label, className:'field_label'}),
						create('textarea', {id:'field_'+i,innerHTML:value, cols:(field.cols?field.cols:20), rows:(field.rows?field.rows:2)})
					), className: 'config_var'});
					break;
				case 'radio':
					var boxes = new Array();
					for (var j = 0,len = Options.length; j<len; j++) {
						boxes.push(create('span', {textContent:Options[j]}));
						boxes.push(create('input', {value:Options[j], type:'radio', name:i, checked:Options[j]==value?true:false}));
					}
					elem = create(isKid ? "span" : "div", {title:field.title||'', kids:new Array(
						create('span', {textContent:label, className:'field_label'}),
						create('span', {id:'field_'+i, kids:boxes})
					), className: 'config_var'});
					break;
				case 'select':
					var options = [];
					if(typeof Options === "object" && typeof Options.push !== "function") for(var j in Options) options.push(create('option',{textContent:Options[j],value:j,selected:(j==value)}));
						else options.push(create("option", {textContent:"Error - \"options\" needs to be a JSON object.", value:"error", selected:"selected"}));
					elem = create(isKid ? "span" : "div", {title:field.title||'', kids:new Array(
						create('span', {textContent:label, className:'field_label'}),
						create('select',{id:'field_'+i, kids:options})
					), className: 'config_var'});
					break;
				case 'checkbox':
					elem = create(isKid ? "span" : "div", {title:field.title||'', kids:new Array(
						create('label', {textContent:label, className:'field_label', "for":'field_'+i}),
						create('input', {id:'field_'+i, type:'checkbox', value:value, checked:value})
					), className: 'config_var'});
					break;
				case 'button':
				var tmp;
					elem = create(isKid ? "span" : "div", {kids:new Array(
						(tmp=create('input', {id:'field_'+i, type:'button', value:label, size:(field.size?field.size:25), title:field.title||''}))
					), className: 'config_var'});
					if(field.script) obj.addEvent(tmp, 'click', field.script);
					break;
				case 'hidden':
					elem = create(isKid ? "span" : "div", {title:field.title||'', kids:new Array(
						create('input', {id:'field_'+i, type:'hidden', value:value})
					), className: 'config_var'});
					break;
				case 'password':
					elem = create(isKid ? "span" : "div", {title:field.title||'', kids:new Array(
						create('span', {textContent:label, className:'field_label'}),
						create('input', {id:'field_'+i, type:'password', value:value, size:(field.size?field.size:25)})
					), className: 'config_var'});
					break;
				default:
					elem = create(isKid ? "span" : "div", {title:field.title||'', kids:new Array(
						create('span', {textContent:label, className:'field_label'}),
						create('input', {id:'field_'+i, type:'text', value:value, size:(field.size?field.size:25)})
					), className: 'config_var'});
			}
	if(field.kids) {
		var kids=field.kids;
		for(var kid in kids) elem.appendChild(obj.addToFrame(kids[kid], kid, true));
	}
return elem;
},
 doSave : function(f, field, type, oldf) {
 var isNum=/^[\d\.]+$/, set = oldf ? GM_config.settings[oldf]["kids"] : GM_config.settings;
 switch(type) {
				case 'text':
					GM_config.values[f] = ((set[f].type=='text') ? field.value : ((isNum.test(field.value) && ",int,float".indexOf(","+set[f].type)!=-1) ? parseFloat(field.value) : false));
					if(set[f]===false) {
						alert('Invalid type for field: '+f+'\nPlease use type: '+set[f].type);
						return;
					}
					break;
				case 'hidden': case 'password':
					GM_config.values[f] = field.value.toString();
					break;
				case 'textarea':
					GM_config.values[f] = field.value;
					break;
				case 'checkbox':
					GM_config.values[f] = field.checked;
					break;
				case 'select':
					GM_config.values[f] = field.options[field.selectedIndex].value;
					break;
				case 'span':
					var radios = field.getElementsByTagName('input');
					if(radios.length>0) for(var i=radios.length-1; i>=0; i--) {
						if(radios[i].checked) GM_config.values[f] = radios[i].value;
					}
					break;
			}
 },
 doSettingValue : function(settings, stored, i, oldi, k) {
		var set = k!=null && k==true && oldi!=null ? settings[oldi]["kids"][i] : settings[i];
			if(",save,open,close".indexOf(","+i) == -1) {
            // The code below translates to:
            // if a setting was passed to init but wasn't stored then 
            //      if a default value wasn't passed through init() then use null
            //      else use the default value passed through init()
            // 		else use the stored value
            try {
            var value = (stored[i]==undefined ? (set["default"]==undefined ? null : set["default"]) : stored[i]);
			} catch(e) {
			var value = (stored[i]=="undefined" ? (set["default"]=="undefined" ? null : set["default"]) : stored[i]);
			}
            
            // If the value isn't stored and no default was passed through init()
            // try to predict a default value based on the type
            if (value === null) {
                switch(set["type"]) {
                    case 'radio': case 'select':
                        value = set.options[0]; break;
                    case 'checkbox':
                        value = false; break;
                    case 'int': case 'float':
                        value = 0; break;
                    default:
					value = (typeof stored[i]=="function") ? stored[i] : "";
                }
			}
			
			}
	GM_config.passed_values[i] = value;
 },
 doReset : function(field, type, oldf, f, k) {
 var isKid = k!=null && k==true, obj=GM_config,
	 set = isKid ? obj.settings[oldf]["kids"][f] : obj.settings[f];
 switch(type) {
			case 'text':
				field.value = set['default'] || '';
				break;
			case 'hidden': case 'password':
				field.value = set['default'] || '';
				break;
			case 'textarea':
				field.value = set['default'] || '';
				break;
			case 'checkbox':
				field.checked = set['default'] || false;
				break;
			case 'select':
				if(set['default']) {
					for(var i=field.options.length-1; i>=0; i--)
					if(field.options[i].value==set['default']) field.selectedIndex=i;
				}
				else field.selectedIndex=0;
				break;
			case 'span':
				var radios = field.getElementsByTagName('input');
				if(radios.length>0) for(var i=radios.length-1; i>=0; i--) {
					if(radios[i].value==set['default']) {
						radios[i].checked=true;
					}
				}
				break;
		}
 },
 values: {},
 settings: {},
 css: {
	 basic: 'body {background:#FFFFFF;}\n' +
	 '.indent40 {margin-left:40%;}\n' +
	 '* {font-family: arial, tahoma, sans-serif, myriad pro;}\n' +
	 '.field_label {font-weight:bold; font-size:12px; margin-right:6px;}\n' +
	 '.block {display:block;}\n' +
	 '.saveclose_buttons {\n' +
	 'margin:16px 10px 10px 10px;\n' +
	 'padding:2px 12px 2px 12px;\n' +
	 '}\n' +
	 '.reset, #buttons_holder, .reset a {text-align:right; color:#000000;}\n' +
	 '.config_header {font-size:20pt; margin:0;}\n' +
	 '.config_desc, .section_desc, .reset {font-size:9pt;}\n' +
	 '.center {text-align:center;}\n' +
	 '.section_header_holder {margin-top:8px;}\n' +
	 '.config_var {margin:0 0 4px 0; display:block;}\n' +
	 '.config_var {font-size: 13px !important;}\n' +
	 '.section_header {font-size:13pt; background:#414141; color:#FFFFFF; border:1px solid #000000; margin:0;}\n' +
	 '.section_desc {font-size:9pt; background:#EFEFEF; color:#575757; border:1px solid #CCCCCC; margin:0 0 6px 0;}\n' +
	 'input[type="radio"] {margin-right:8px;}',
	 stylish: ''
 },
 create: function(a,b) {
	var ret=window.document.createElement(a);
	if(b) for(var prop in b) {
		if(prop.indexOf('on')==0) ret.addEventListener(prop.substring(2),b[prop],false);
		else if(prop=="kids" && (prop=b[prop])) for(var i=0; i<prop.length; i++) ret.appendChild(prop[i]);
		else if(",style,accesskey,id,name,src,href,for".indexOf(","+prop.toLowerCase())!=-1) ret.setAttribute(prop, b[prop]);
		else ret[prop]=b[prop];
	}
	return ret;
 },
 center: function() {
	var node = GM_config.frame, style = node.style, beforeOpacity = style.opacity;
	if(style.display=='none') style.opacity='0';
	style.display = '';
	style.top = Math.floor((window.innerHeight/2)-(node.offsetHeight/2)) + 'px';
	style.left = Math.floor((window.innerWidth/2)-(node.offsetWidth/2)) + 'px';
	style.opacity = '1';
 },
 run: function() {
    var script=GM_config.getAttribute('script');
    if(script && typeof script=='string' && script!='') {
      func = new Function(script);
      window.setTimeout(func, 0);
    }
 },
 addEvent: function(el, ev, scr) {
	if(el) el.addEventListener(ev, function() {
		typeof scr === 'function' ? window.setTimeout(scr, 0) : eval(scr)
	}, false);
},
 remove: function(el) {
	if(el && el.parentNode) el.parentNode.removeChild(el);
},
 toggle : function(e) {
	var node=GM_config.frame.contentDocument.getElementById(e);
	node.style.display=(node.style.display!='none')?'none':'';
	GM_config.setValue(e, node.style.display);
 },
};


//============================引用ここまで===================================


//ユーザー設定(User's settings)-------------------------------------------------------------------------------------

	//設定ボタンの位置調整
	var setPos = "margin:0 0 3px 10px";

	//ログイン時の設定ボタン(Twitterのアイコンがログインしてるかどうかで位置が変わる)
	var twitBtn = document.getElementsByClassName("Icon Icon--bird bird-topbar-etched")[0];
	if(twitBtn == undefined){
		//ログアウト時の設定ボタン
		twitBtn = document.getElementsByClassName("home")[0];
		setPos = "margin:20px 0 0 20px";
	}

	//設定ボタン追加
	if(twitBtn != undefined && twitBtn.getAttribute("ToT") != "set"){
		twitBtn.insertAdjacentHTML('afterend','<img name="setBtn" id="setBtn" type="button" '
			 + 'src="data:image/gif;base64,R0lGODlhCwALAIABAACZ/////yH5BAEAAAEALAAAAAALAAsAAAIaBHKha6j5TmrRIdqmkTLu7HHWVmlMZ5XLWgAAOw==" '
			 + 'title="Config - Thumbnail size">');

		twitBtn.setAttribute("ToT","set") ;
	}


	//設定ボタンクリックで設定画面を呼び出す(Open Config Window,when click the Config Button)
	var setBtn = document.getElementById("setBtn");
	if(setBtn != undefined){
		setBtn.addEventListener('click', function(){GM_config.open()}, true);
		setBtn.setAttribute("Style",setPos);
	}


	//設定画面(Config Window)
	GM_config.init('Config - Thumbnail size' /* Script title */,
	/* Settings object */

	//initを連装配列に変更
	cfgData,

	{
	open: function() {

        //config window
        var cfg_Window = document.getElementById("GM_config");

	//説明書き
	var cfg_exSect = cfg_Window.contentDocument.getElementById("c_section_kids_0");
	var cfg_importantPoint = cfg_Window.contentDocument.getElementById("field_ImportantPoint");

        cfg_exSect.setAttribute("style", "display:block;");
        cfg_importantPoint.setAttribute("style", "border:none;resize: none;height:150px;width:100%;disabled:;");
	cfg_importantPoint.setAttribute("readonly", "");


	//各サムネ設定の配置指定--------------------------------------------------

	//解像度低い場合2列表示(幅1280以上を目安。800以下は1列のまま)
	var css1280 = '@media screen and (min-width: 800px) and (max-width: 1399px){'
		     + '.section_header_holder:nth-child(2n + 3){ height:80px;width:350px;margin:10px 0 0 20px; }'
		     + '.section_header_holder:nth-child(2n + 4){ height:0;width:350px;position:relative;top:-87px;left:400px; }'
		     + '}';//ここまで

	//解像度高い場合3列表示(幅1600以上を目安)
	var css1600 = '@media screen and (min-width: 1400px) {'
		     + '.section_header_holder:nth-child(3n+3){ height:80px;width:350px;margin:10px 0 0 20px; }'
		     + '.section_header_holder:nth-child(3n+4){ height:0;width:350px;position:relative;top:-87px;left:400px; }'
		     + '.section_header_holder:nth-child(3n+5){ height:0;width:350px;position:relative;top:-96px;left:800px; }'
		     + '}';//ここまで

	addStyle(cfg_Window.contentDocument,css1280);
	addStyle(cfg_Window.contentDocument,css1600);


	}//openここまで
	});

	//GreaseMonkeyとScriptishのオプション追加(add Option)
	GM_registerMenuCommand("Config - Thumbnail size", GM_config.open);




/*	//もしlocalstorageにユーザー設定があったらlocalDBにセット
	if(tmpDB != null){
		localDB = {};
		localDB = tmpDB;
	//greasemonkeyはプロファイルフォルダに独自DBを作成していて、内容を見るにはMySQLなどが必須
	}else if(GM_config.get("twitter2Thumb") != undefined && GM_config.get("twitter2Thumb") != null){
*/
	for(name in titleDB){
		if(GM_config.get(name + "Thumb") != undefined && GM_config.get(name + "Thumb") != null){
			localDB[name + "Link"] = GM_config.get(name + "Link") ;
			localDB[name + "Thumb"] = GM_config.get(name + "Thumb") ;
			localDB[name + "Size"] = GM_config.get(name + "Size") ;
		}
	}
	if(GM_config.get("flgDefPic") != undefined && GM_config.get("flgDefPic") != null){
		localDB["flgDefPic"] = GM_config.get("flgDefPic");
	}

}//userCfgここまで



//ユーザー関数=====================================================================================
function renameTwitgoo(document){

	//リンクの修正
	var twitgooLinks = document.getElementsByClassName("twitgooText");

	for (i = 0; i < twitgooLinks.length; i++){

		if(twitgooLinks[i].href.match("twitgoo.com")){
			twitgooLinks[i].href = twitgooLinks[i].href.replace("twitgoo","tinypic");
		}
	}

	//サムネの修正
	var twitgooPics = document.getElementsByClassName("twitgooPhoto");

	for (i = 0; i < twitgooPics.length; i++){
	}
}


//サーバーDB作成
function makeServerDB(name,title,def){


	//localDBに初期値をセット
	localDB[name + "Link"] = true;
	localDB[name + "Thumb"] = true;
	localDB[name + "Size"] = def;

	localDB["flgDefPic"] = false;

	//タイトルDB作成
	if(title == ""){title = name;}
	titleDB[name] = title;

	//サムネサイズDBのひな形作成
	if(name != "AllThumbsAndLinks" && name != "alertnotice"){
		optionDB[name] = {};
	}

}//サーバーDB作成ここまで


//コンフィグ画面の初期値設定
function makeInitData(){

	//メインタイトルのラベル欄--------------------------------------------------
	cfgData["ImportantPoint"] = {};
	cfgData["ImportantPoint"]["section"] = ['注意点 important point'];
	cfgData["ImportantPoint"]["type"] = "textarea";
	cfgData["ImportantPoint"]["default"] = 
		   '1,「名前を付けてリンク先を保存」でオリジナルサイズで保存できます。(「名前を付けて画像を保存」だとサムネ保存)\r\n'
		 + '  "Save Link As..." can save Original size. ("Save Image As..." save Thumbnail)\r\n'
		 + '2,大きいサイズにするとはみ出るので最大400pxにしています。\r\n'
		 + '  max-width 400px,because Large-Thumbnail overflows the frame. \r\n'
		 + '3,サイズ数値は大体の目安です。The size is approximate value \r\n'
		 + '4,この解説を読み終わったらタイトルバーをクリックしてSAVEすると非表示にできます。 \r\n'
		 + '  If finished reading, clicked title bar and saved, it can do undisplayed next-time.  \r\n';
//alert(JSON.stringify(optionDB["droplr"]));


	//twtitterが追加するサムネの表示設定
	cfgData["flgDefPic"] = {};
	cfgData["flgDefPic"]["section"] = ['twitter側のサムネ Thumbs added by twitter'];
	cfgData["flgDefPic"]["label"] = "表示する show";
	cfgData["flgDefPic"]["type"] = "checkbox";
	cfgData["flgDefPic"]["default"] = false;


	//サービス名ごとに作成
	for(key in titleDB){
		initSet(key);
	}


	//サービス設定欄初期値作成
	function initSet(name){


		//リンク欄--------------------------------------------------

		//その他の画像URLにサムネ追加対応(リンク追加設定は除外)
		if(name == "alertnotice"){
			var strLink = name + "Link";

			cfgData[strLink] = {};
			cfgData[strLink]["section"] = [titleDB[name]];
			cfgData[strLink]["label"] = '通知音を鳴らす(pray alert sound)';
			cfgData[strLink]["type"] = "checkbox";
			cfgData[strLink]["default"] = localDB[name + "Size"];

			return;

		}else if(name != "otherPic"){
			var strLink = name + "Link";

			cfgData[strLink] = {};
			cfgData[strLink]["section"] = [titleDB[name]];
			cfgData[strLink]["label"] = "保存用リンク追加 Add Save Link";
			cfgData[strLink]["type"] = "checkbox";
			cfgData[strLink]["default"] = true;
		}

		//サムネ欄--------------------------------------------------
		var strThumb = name + "Thumb";

		cfgData[strThumb] = {};

		//その他の画像URLにサムネ追加対応
		if(name == "otherPic"){
			cfgData[strThumb]["section"] = [titleDB[name]];
		}

		cfgData[strThumb]["label"] = 'サムネ追加 Add Thumb';
		cfgData[strThumb]["type"] = "checkbox";
		cfgData[strThumb]["default"] = true;


		//サムネサイズ欄--------------------------------------------------

		if(name == "AllThumbsAndLinks"){
			var strSize = name + "Size";

			cfgData[strSize] = {};
			cfgData[strSize]["label"] = '短縮URL展開 Expand URL(t.co)';
			cfgData[strSize]["type"] = "checkbox";
			cfgData[strSize]["default"] = localDB[name + "Size"];
		}else{
			var strSize = name + "Size";

			cfgData[strSize] = {};
			cfgData[strSize]["label"] = 'サイズ変更 size of thumb';
			cfgData[strSize]["type"] = "select";
			cfgData[strSize]["options"] = optionDB[name];			//選択肢を配列でセット
			cfgData[strSize]["default"] = localDB[name + "Size"];	//デフォルト値
		}

	}//サービス設定欄初期値作成ここまで
}//コンフィグ画面の初期値設定ここまで



//CSSを追加------------------------------------------------
function addStyle(document,css) {
	var head = document.getElementsByTagName('head')[0];
	if (!head) { return };

	var style = document.createElement('style');
	style.type = 'text/css';
	style.innerHTML = css;
	head.appendChild(style);
}


//新着通知
function chime(node){
	if(!node){return;}

	//検索結果
	var newSearch = document.evaluate('.//div[@class="new-tweets-bar js-new-tweets-bar "]', node, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
	var nClass = node.getAttribute("class");

	if(nClass != "Grid"				//ユーザーページの更新以外
	  && newSearch.snapshotItem(0) == null){	//検索やタイムラインの更新以外
		return;
	}else{
		audio.play();

//		alert(newSearch.snapshotItem(0).innerHTML);
	}
}


//ユーザー関数ここまで============================================================================






//引用開始===================================================================================

//==============================================================
//すでに組まれている方がいたのでソースを拝借(少し書き換え)
//Copyright:NeoCat
//http://d.hatena.ne.jp/NeoCat/20091228/1262015896
//==============================================================
/*

//base58デコード
function decodeBase58(snipcode) {
	var base58_letters = '123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ';
	var ret = 0;
	for (var i = snipcode.length, m = 1; i; i--, m *= 58)
		ret += base58_letters.indexOf(snipcode.substr(i-1,1)) * m;
	return ret;
}


//画像ID取得(マッチしないとundefined)
function flickrPhotoID(url) {
	if (url.match(/^http:\/\/(?:www\.flickr\.com\/photos\/[\w-_@]+\/(\d+)|flic\.kr\/p\/(\w+)$)/))
		return RegExp.$2 ? decodeBase58(RegExp.$2) : RegExp.$1;
}


//URL整形
function getUrl(response){
	var p = response.photo;
	if (!p) return;
	var url = 'http://farm' + p.farm + '.static.flickr.com/' + p.server + '/' + p.id + '_' + p.secret + '_s.jpg';
	// このurlを使って何かする
}
*/

/*****************************************************************************
クロスドメインでJSONP取得
使い方:xds.load(APIのURL, コールバック関数, エラーハンドラ関数);
例:
var f = xds.load("http://www.google.com/uds/Gtranslate?v=1.0" +
		"&langpair=|ja&context=test&q=" + encodeURIComponent("Hello!"),
		function(id,result) { alert(result.translatedText) },
		function() { alert("Error...") }
);
******************************************************************************/

//var xds = {
//	load: function(url, callback, onerror, retry, callback_key) {
//		var ifr = document.createElement("iframe");
//		ifr.style.display = "none";
//		document.body.appendChild(ifr);
//		var d = ifr.contentWindow.document;
//		var cnt = 0;
//		ifr[ifr.readyState/*IE*/ ? "onreadystatechange" : "onload"] = function() {
//			if (this.readyState && this.readyState != 'complete' || cnt++) return;
//			if (d.x) {
//				if (callback) callback.apply(this, d.x);
//			} else if (retry && retry > 1) {
//				setTimeout(function(){ xds.load(url, callback, onerror, retry-1) }, 1000);
//			} else if (onerror)
//				onerror();
//			setTimeout(function(){ try { ifr.parentNode.removeChild(ifr); } catch(e) {} }, 0);
//		};
//		var url2 = url + (url.indexOf('?')<0?'?':'&') +
//			(callback_key?callback_key:'callback') + '=cb';
//		d.write('<scr'+'ipt>function cb(){document.x=arguments}</scr'+'ipt>' +
//			'<scr'+'ipt src="'+url2+'"></scr'+'ipt>');
//		d.close();
//		return ifr;
//	},
//	abort: function(ifr) {
//		if (ifr && ifr.parentNode)
//			ifr.parentNode.removeChild(ifr);
//	}
//}

//引用ここまで===============================================================================



})();