// ==UserScript==
// @id thumb_on_twitter
// @name Thumb_on_Twitter
// @version 2.32
// @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 @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
// @grant GM_xmlhttpRequest
// ==/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
flickr(一部サイズ変更に対応せず)
hatena
img.ly
imgur
instagram
Mobypicture
携帯百景movapic
Ow.ly
photozou
tumblr
twitpic
twipple
twitter(公式official pic.twitter.com)
twitter(公式official p.twimg.com)
twitter(公式official pbs.twimg.com)
vine
yfrog
[サポート対象外(not supported)]
・flickr(staticflickr)の一部サイズ指定非対応
URL"http://flickr.com/photo.gne?id={id}"で元のURLを取得できずにyahooのloginを求められるため
画像のサイズ指定ができません。
更新履歴
08/28/2014 - v2.32 fix:一部サムネURLの仕様でgif動画が動かなかったものを動くように変更(ただしオリジナルGIF動画を縮小表示してるだけなので少し重い)
08/28/2014 - v2.31 fix:twitter公式不具合修正
08/24/2014 - v2.30 add:youtube
08/24/2014 - v2.29 fix:vineの動画削除済みURLはdead linkと表示するように変更
08/24/2014 - v2.28 add:vine
08/24/2014 - v2.27 add:twitter3とinstagramが動画URLだった場合、動画playerを追加するリンクを実装(thumb設定がonの時のみ)
08/22/2014 - v2.26 fix:サムネがはみ出るのでサイズ調整
08/21/2014 - v2.25 add:タイムラインと画像のみのページにも対応
08/19/2014 - v2.24 fix:uploaded to other script.sorry...
08/18/2014 - v2.23 fix:flickrのオリジナル画像が最大サイズじゃなかった場合表示できなかった不具合修正。v2.21の不具合修正
08/18/2014 - v2.22 fix:v2.21の不具合修正
08/15/2014 - v2.21 fix:twitter公式pic.twitter.comの複数画像に対応
08/15/2014 - v2.20 fix:twitter公式pbs.twimg.comで一部表示できなくなっていた不具合修正
08/14/2014 - v2.19 add:tumblrに対応。携帯百景movapicのuserIDが入ってくるURLにも対応。
08/14/2014 - v2.18 add:flickrに対応。設定画面起動アイコンをクリックで閉じる機能。ESC押したら設定画面閉じる機能追加
08/05/2014 - v2.17 fix:i.instagramに対応
08/05/2014 - v2.16 fix:instagramで一部表示できなかったサムネに対応
08/05/2014 - v2.15 fix:通知音設定の不具合修正。chromeでのエラー修正。他
08/02/2014 - v2.14 fix:2.13の修正
07/31/2014 - v2.13 fix:サムネ取得失敗時に拡張子がpngかどうかも試してみるように変更
07/20/2014 - v2.12 add:更新通知音
07/19/2014 - v2.11 add:簡易短縮URL展開 Expand URL(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
***************************************************************
備忘録
・GM_xmlhttpRequestは非同期処理なので、終了を待たずに次の処理に行ってしまい面倒
→そのうちajaxに変更するかもしれない
ホントは短縮URLのt.coをtwitterのapiでinclude_entitiesをtrueにして
展開されたURLを取得しようと思ったけどすでに他スクリプトがあるのでスルー
→twitter側が展開してくれてる場合data-expanded-urlのURLに変更
・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/画像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″
Lockerz(旧Plixi, その前は TweetPhoto)画像サービス終了?全部ador.comのトップページに飛ぶので詳細不明
ページ: 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”
brightkite 終了確定
**************************************************************/
/**************************追加予定****************************************************************************
可能ならTwitgoo
突貫工事で追加した部分の処理で共通部分を短縮する
ニコニコ動画の短縮URLを動画に変更
動画の拡張子の場合動画プレーヤーを埋め込み
facebookの対応 GM_xmlhttpRequestでURL展開
HeartRails Captureでtumblrの複数画像かどうか確認できるようにする?それとも直接表示する?
http://capture.heartrails.com/tiny?http://url … 60×45 ピクセル
http://capture.heartrails.com/small?http://url … 120×90 ピクセル
http://capture.heartrails.com/medium?http://url … 200×150 ピクセル
http://capture.heartrails.com/large?http://url … 400×300 ピクセル
http://capture.heartrails.com/huge?http://url … 640×480 ピクセル
サイズ指定も可能
http://capture.heartrails.com/200x400/?
読み込みまでの待ち時間指定
http://capture.heartrails.com/64x64/delay=5?
拡張子pdfのスナップショット
http://capture.heartrails.com/pdf?
ページに合わせて縦サイズを縮める
http://capture.heartrails.com/64x64/shorten?
装飾
http://capture.heartrails.com/64x64/shadow?
http://capture.heartrails.com/64x64/border?
http://capture.heartrails.com/64x64/round?
******************************************************************************************************/
(function() {
//ifame内除外
if(location.href.match(/^https?:\/\/twitter.com\/i\/cards\//)){ return; }
//定数----------------------------------------------------------------
const fileExt = ["gif","jpg","jpeg","png","bmp"];
const strIcon = '<img name=imgBtn id=imgBtn type=button style=max-width:12px;display:inline-block; '
+ 'src=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAALCAYAAACprHcmAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAABOSURBVChTjZG5DQAwCANJhs1QWZZgCSQUxHMNLs6NWSyQsq4GgY8Gx9Yb8EUjlcFfKGXgC60MrDCSAQpjGeuMZJuxlf3epfw/JpXjB4keFPsQEoUOdacAAAAASUVORK5CYII= '
+ '>';
//グローバル変数セット------------------------------------------------
var name =""; //サービス名
var fileType = ""; //拡張子
var cfgData = {}; //ユーザー設定画面の初期値
var localDB = {}; //初期値(ローカルストレージに保存されるデータと同じ形式のデータベース)
var titleDB = {}; //タイトルDB(サーバーの名称)
var optionDB = {}; //サムネサイズ選択肢DB
var expDB = {}; //URL展開履歴
//localStorageに格納されているデータを直接確認(localDBと同じもの)
// var tmpDB = JSON.parse(localStorage.getItem("configthumbnailsize"));
var flickrSrcDB ={}; //flickr専用
var twitter1DB ={}; //pic.twitter専用
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(){
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 = "custom";
makeServerDB(name,title,def); //固定
optionDB[name]["+"] = "full:original";
optionDB[name]["custom"] = "thumb:100x100(gif move)"; //このスクリプト専用で標準にはないオプション
optionDB[name]["-"] = "thumb:100x100(gif stop)";
//---------------------------------------------
name = "flickr";
title = "flickr";
def = "q";
//sq:75x75、q:100x100、t:100x75、s:240x180、n:320x240、m:500x375、指定なし(none):500x500、z:640x480、c:800x600、l:1024x768、b:1024x1024、o:origin
makeServerDB(name,title,def); //固定
optionDB[name]["o"] = "o:original";
optionDB[name]["b"] = "b:1024x1024";
optionDB[name]["l"] = "l:1024x768";
optionDB[name]["c"] = "c:800x600";
optionDB[name]["z"] = "z:640x480";
optionDB[name]["m"] = "m:500x375";
optionDB[name]["n"] = "n:320x240";
optionDB[name]["s"] = "s:240x180";
optionDB[name]["q"] = "q:100x100";
optionDB[name]["t"] = "t:100x75";
optionDB[name]["sq"] = "sq:75x75";
//---------------------------------------------
name = "hatena";
title = "はてなフォトライフf.hatena";
def = "_120";
makeServerDB(name,title,def); //固定
optionDB[name][""] = "original";
optionDB[name]["_120"] = "_120:120x77";
optionDB[name]["_m"] = "_m:60x39";
//---------------------------------------------
name = "imgly";
title = "img.ly";
def = "thumb";
makeServerDB(name,title,def); //固定
optionDB[name]["full"] = "full:original";
optionDB[name]["large"] = "large:550x620";
optionDB[name]["medium"] = "medium:320x240";
optionDB[name]["thumb"] = "thumb:150x150";
optionDB[name]["mini"] = "mini:75x75";
//---------------------------------------------
name = "imgur";
title = "";
def = "m";
makeServerDB(name,title,def); //固定
optionDB[name][""] = "original";
optionDB[name]["l"] = "l:640x480";
optionDB[name]["m"] = "m:320x200";
optionDB[name]["s"] = "s:90x90";
//---------------------------------------------
name = "instagram";
title = "";
def = "t";
makeServerDB(name,title,def); //固定
optionDB[name]["l"] = "large:612x612";
optionDB[name]["m"] = "medium:306x306";
optionDB[name]["t"] = "thumbnail:150x150";
//---------------------------------------------
name = "Mobypicture";
title = "";
def = "thumbnail";
makeServerDB(name,title,def); //固定
optionDB[name]["original"] = "original:original?";
optionDB[name]["full"] = "full:original?";
optionDB[name]["large"] = "large:original?";
optionDB[name]["medium"] = "medium";
optionDB[name]["small"] = "thumbnail:500x400";
optionDB[name]["thumbnail"] = "thumbnail:100x100";
optionDB[name]["square"] = "thumbnail:90x90";
//---------------------------------------------
name = "movapic";
title = "携帯百景movapic";
def = "t";
makeServerDB(name,title,def); //固定
// optionDB[name]["l"] = "large:612x612"; //removed this options?
optionDB[name]["m"] = "medium:306x306";
optionDB[name]["t"] = "thumbnail:150x150";
//---------------------------------------------
name = "Owly";
title = "Ow.ly";
def = "thumb";
makeServerDB(name,title,def); //固定
optionDB[name]["original"] = "original";
optionDB[name]["normal"] = "normal";
optionDB[name]["thumb"] = "thumb:100x100";
//---------------------------------------------
name = "photozou";
title = "フォト蔵photozou";
def = "thumb";
makeServerDB(name,title,def); //固定
optionDB[name]["img"] = "img:original";
optionDB[name]["thumb"] = "thumb:120x120";
//---------------------------------------------
name = "tumblr";
title = "tumblr";
def = "100";
makeServerDB(name,title,def); //固定
optionDB[name]["1280"] = "1280:1280x1280";
optionDB[name]["500"] = "500:500x500";
optionDB[name]["400"] = "400:400x400";
optionDB[name]["250"] = "250:250x250";
optionDB[name]["100"] = "100:100x100";
optionDB[name]["75sq"] = "75sq:75x75";
//---------------------------------------------
name = "twipple";
title = "ついっぷるtwipple";
def = "thumb";
makeServerDB(name,title,def); //固定
optionDB[name]["orig"] = "orig:original";
optionDB[name]["large"] = "large:350x480";
optionDB[name]["thumb"] = "thumb:160x120";
//---------------------------------------------
name = "twitpic";
title = "";
def = "thumb";
makeServerDB(name,title,def); //固定
optionDB[name]["full"] = "full:original";
optionDB[name]["large"] = "large:600x800";
optionDB[name]["thumb"] = "thumb:150x150";
optionDB[name]["mini"] = "mini:75x75";
//---------------------------------------------
name = "twitter1";
title = "Official(1):pic.twitter";
def = "thumb";
makeServerDB(name,title,def); //固定
optionDB[name]["orig"] = "orig:Original";
optionDB[name]["large"] = "large:Original?";
optionDB[name]["medium"] = "medium:600x450";
optionDB[name]["small"] = "small:340x244";
optionDB[name]["thumb"] = "thumb:150x150";
//---------------------------------------------
name = "twitter2";
title = "Official(2):p.twimg";
def = "thumb";
makeServerDB(name,title,def); //固定
optionDB[name]["orig"] = "orig:Original";
optionDB[name]["large"] = "large:Original?";
optionDB[name]["medium"] = "medium:600x450";
optionDB[name]["small"] = "small:340x244";
optionDB[name]["thumb"] = "thumb:150x150";
//---------------------------------------------
name = "twitter3";
title = "Official(3):pbs.twimg.com";
def = "thumb";
makeServerDB(name,title,def); //固定
optionDB[name]["orig"] = "orig:Original";
optionDB[name]["large"] = "large:Original?";
optionDB[name]["medium"] = "medium:600x450";
optionDB[name]["small"] = "small:340x244";
optionDB[name]["thumb"] = "thumb:150x150";
//---------------------------------------------
name = "vine";
title = "";
def = "150";
makeServerDB(name,title,def); //固定
optionDB[name]["150"] = "thumb:150x150";
optionDB[name]["510"] = "original";
//---------------------------------------------
name = "yfrog";
title = "";
def = "small";
makeServerDB(name,title,def); //固定
optionDB[name]["medium"] = "medium:640x480";
optionDB[name]["iphone"] = "iphone:480x360";
optionDB[name]["small"] = "small:125x90";
//---------------------------------------------
name = "youtube";
title = "";
def = "mqdefault";
makeServerDB(name,title,def); //固定
optionDB[name]["mqdefault"] = "default:320×180";
optionDB[name]["0"] = "0:480x360";
// optionDB[name]["2"] = "2:120x90"; //表示できない動画もある
//highres hd1080 hd720 large medium small
//---------------------------------------------
name = "youtubeQuality";
title = "youtubeQuality";
def = "highres";
makeServerDB(name,title,def); //固定
optionDB[name]["small"] = "small";
optionDB[name]["medium"] = "medium";
optionDB[name]["large"] = "large";
optionDB[name]["hd720"] = "hd720";
optionDB[name]["hd1080"] = "hd1080";
optionDB[name]["highres"] = "highres:most high";
//---------------------------------------------
name = "otherPic";
title = "その他の画像URL(Other ImageURL)";
def = "thumb";
makeServerDB(name,title,def); //固定
optionDB[name]["origin"] = "origin:original";
optionDB[name]["thumb"] = "thumb:100x100";
}
//***************************************************
//main==========================================================================================
function main(node){
//継ぎ足し要素がaタグだった場合nodeを親要素にする
if(node.parentNode && node.tagName && node.tagName.match(/^a$/i)){ node = node.parentNode;}
var allLinks = document.evaluate('.//a', node, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
for (i = 0; i < allLinks.snapshotLength; i++){
var objLink = allLinks.snapshotItem(i);
//短縮URLを簡易的に展開
if(localDB["AllThumbsAndLinksSize"] && objLink.hasAttribute("href")){
var tmpUrl = objLink.href;
//展開
if(objLink.hasAttribute("data-expanded-url") && objLink.getAttribute("data-expanded-url").match(/^http/)){
tmpUrl = objLink.getAttribute("data-expanded-url");
}else if(objLink.hasAttribute("data-resolved-url-large") && objLink.getAttribute("data-resolved-url-large").match(/^http/)){
tmpUrl = objLink.getAttribute("data-resolved-url-large");
//t.coリンクでテキストが展開URLだったら
}else if(objLink.innerHTML.match(/[a-zA-Z0-9]..*\//) && objLink.href.match(/https?:\/\/t.co\//)){
tmpUrl = "http://" + objLink.innerHTML;
}
objLink.href = tmpUrl;
objLink.rel = "noreferrer";
}
//サムネ追加対象以外は除外
if(!objLink.hasAttribute("class")
||!objLink.getAttribute("class").match(/twitter-timeline-link/)
|| objLink.getAttribute("class").match(/media-thumbnail/)
//hrefを含まないリンクは除外
|| !objLink.hasAttribute("href") || objLink.href == ""
|| objLink.getAttribute("data-expanded-url") == ""
//サムネURL展開中も除外
|| objLink.hasAttribute("ToT_URL") && objLink.getAttribute("ToT_URL").match(/^NowLoading:.*/)
//サムネ追加済みは除外
|| objLink.hasAttribute("ToT_Link") && objLink.getAttribute("ToT_Link") == "added"
|| objLink.hasAttribute("ToT_Thumb") && objLink.getAttribute("ToT_Thumb") == "added"
//Affiliate_Killerの非表示リンク部分対応
|| objLink.hasAttribute("akill_check") && !objLink.getAttribute("akill_check").match(/added/i)
){
continue;
}
var href = objLink.href;
//URL展開して取得したURLがセットされていたら
if(objLink.hasAttribute("ToT_URL") && objLink.getAttribute("ToT_URL").match(/^http/)){
href = objLink.getAttribute("ToT_URL");
expDB[objLink.href] = href;
}else if(expDB[objLink.href] && expDB[objLink.href].match(/^http/)){
href = expDB[objLink.href];
}
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\/.*?\//)){
name = "droplr";
var picID = href.replace(/.*d.pr\/i\//,"");
if(href.slice(-1) == "-" || href.slice(-1) == "+"){
href = href.slice(0,-1);
}
src = href + localDB[name +"Size"];
if(localDB[name +"Size"] == "custom") src = href + "+";
href = href + "+";
setLink(name);
setThumb(name);
//短縮URL:http://flic.kr/p/英数字(上記画像ID数値のBase58エンコード)
//Flickr短縮URLの展開----------------------------------------------------------------------
}else if(href.match(/^https?:\/\/flic.kr\/(p|s)\/.*/) && !href.match(/^https?:\/\/flic.kr\/(p|s)\/.*?\/.*/)){
expandUrl('HEAD',objLink);
//元のURL:http://www.flickr.com/photos/ユーザー名/画像ID数値/
//サムネ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
//sq:75x75、q:100x100、t:100x75、s:240x180、n:320x240、m:500x375、z:640x480、c:800x600、l:1024x768、b:1024x1024、o:origin
//Flickr画像URLを展開する----------------------------------------------------------------------
}else if(href.match(/^https?:\/\/(www.|m.)?flickr.com\/(#\/)?photos\/.*?\/.*\//)){
name = "flickr";
var size = localDB[name +"Size"];
//Flickr携帯URLならURL修正
if(href.match(/^https?:\/\/m.flickr.com\/(#\/)?photos\/.*?\/.*\//)){
href = href.replace(/\/\/m./,"//").replace(/\/#\//,"/");
}
//サムネ一覧ページにアクセスする用URL
var tmpUrl = href.replace(/^https?/,"https").replace(/^(https?:\/\/(www.)?flickr.com\/photos\/.*?\/.*?\/).*/i,"$1")
+ "sizes/" + size + "/";
//何故かサムネ一覧にあるサムネサイズ指定と画像URLのサムネサイズ指定部分が違うので修正
size = flickrSize(size);
objLink.setAttribute("ToT_URL",tmpUrl,size);
expandUrl('GET',objLink,size);
//Flickr画像URL------------------------------------------------------------------
}else if(href.match(/^https?:\/\/.*static.?flickr.com\/.*?\//)
//元URL取得失敗はスルーして画像拡張子の処理の方に回す
&& objLink.hasAttribute("ToT_URL") && !objLink.getAttribute("ToT_URL").match(/^Error/)){
name = "flickr";
//元から画像URLで投稿されていた場合、一度元のURLに戻す必要がある(画像URLのランダム数値を取得するため)
if(Object.keys(flickrSrcDB).length == 0){
var tempUrl = "https://flickr.com/photo.gne?id=" + href.replace(/.*\/(.*?)_.*?(_[a-zA-Z])?..*/i,"$1");
objLink.setAttribute("ToT_URL",tempUrl);
expandUrl('HEAD',objLink);
//画像URLを展開した場合
}else{
href = href.replace(/^https?/,"https");
src = flickrSrcDB[objLink.href];
//同じURLで再度取得しないように消さない方がいい?
// delete flickrSrcDB[objLink.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\/.*?\/.*?\//)){
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\/.*?\//)){
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) m(サムネ、gif動かない320x200) l(サムネ、gif動かない640x480) "無印"(オリジナル、gif動く)
//imgur--------------------------------------------------------------------------
}else if(href.match(/^https?:\/\/(i.)?imgur.com\/.*$/) && !href.match(/^https?:\/\/(i.)?imgur.com\/.*?\//)){
name = "imgur";
var commonUrl = href.replace(/^https?/,"https").replace("/imgur.com","/i.imgur.com");
fileType = ""; //拡張子
fileType = href.replace(/.*imgur.com\/.*\.(.*$)/i,"$1");
//拡張子なし
if(fileType == href){
expandUrl('GET',objLink);
continue;
//拡張子あり
}else{
src = commonUrl;
if(!fileType.match(/gif/i)) 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/rN9lU5hEB4/?modal=true
//http://instagram.com/p/oMk34hmjwj/media?size=t
//sizeパラメータ t(thumbnail:150x150)、m(medium:306x306)、l(large:612x612)
//instagram----------------------------------------------------------------------
}else if(href.match(/^https?:\/\/(i.)?(i|I)nstagr(am.com|.am)\/p\/.*?\//) && !href.match(/^https?:\/\/instagr(am.com|.am)\/p\/.*?\/.*\//)){
name = "instagram";
var commonUrl = href.replace(/^https/,"http").replace("instagr.am","instagram.com").replace(/\/\?.*$/,"/");
src = commonUrl + "media?size=" + localDB[name +"Size"];
href = commonUrl + "media?size=l";
objLink.setAttribute("ToT_URL",commonUrl);
expandUrl('GET',objLink); //動画チェック
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\/.*?\/.*$/)){
name = "Mobypicture";
src = href + ":" + localDB[name +"Size"];
href = href + ":original";
setLink(name);
setThumb(name);
//http://movapic.com/UserID/pic/PageID)
//携帯百景movapic(ユーザーIDを含んだURL)展開----------------------------------------------
}else if(href.match(/^https?:\/\/movapic.com\/.*?\/pic\/.*$/) && !href.match(/^https?:\/\/movapic.com\/.*?\/pic\/.*?\/.*$/)){
name = "movapic";
expandUrl('GET',objLink);
//ページ: 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\/.*?\/.*$/)
|| href.match(/^https?:\/\/image.movapic.com\/pic\/.*$/)){
name = "movapic";
var commonUrl = "http://image.movapic.com/pic/";
var picID;
//サムネURL
if(href.match(/^https?:\/\/image.movapic.com/)){
picID = href.replace(/.*pic\/.*?_(.*?)\..*/i,"$1");
}else{
picID = href.replace(/.*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\/.*?\/.*$/)){
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\/.*?\/.*?\//)){
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);
//http://tmblr.co/ZLYNzr1OJpp6R
//http://www.tumblr.com/xdo3zozjgf
//展開http://kiitakashi.tumblr.com/post/94821626267/1
//tumblr短縮URL展開----------------------------------------------------------------------
}else if(href.match(/^http:\/\/(www.)?tu?mblr.com?\/[a-zA-Z0-9].*$/)){
name = "tumblr";
expandUrl('HEAD',objLink);
//http://hisuix.tumblr.com/post/94823180344/dig-image-these-shacks-seen-sept-14-1945
//tumblr画像URL取得--------------------------------------------------------------------------
}else if(href.match(/^http:\/\/[\w\-]+.tumblr.com\/post\/[0-9]+.*$/)){
name = "tumblr";
var tmpUrl = href.replace(/(.*tumblr.com)\/post\/([0-9]+).*/i,"$1/image/$2");
objLink.setAttribute("ToT_URL",tmpUrl);
expandUrl('GET',objLink);
//http://38.media.tumblr.com/1fc196798f1148541be4b24ea4f5fe68/tumblr_n91535WAqE1qz7j5oo1_1280.jpg
//最大サイズ(ない場合もある):1280,500px:500, 400px:400, 250px:250, 100px:100, 75px:75sq
//URL展開処理で最大サイズを取得してきているはず
//tumblr--------------------------------------------------------------------------
}else if(href.match(/^http:\/\/\d+.media.tumblr.com\/.*?\/tumblr_.*?_\d+..*/)){
name = "tumblr";
var size = parseInt(href.replace(/^http:\/\/\d+.media.tumblr.com\/.*?\/tumblr_.*?_(\d+)..*/,"$1"));
var strSize = "_" + size +".";
src = href;
//サムネサイズにオリジナルのサイズ以上の指定は無効(オリジナルサイズのまま)、それ以下のみ設定
if(parseInt(localDB[name +"Size"]) < size){
src = href.replace(strSize,"_" + localDB[name +"Size"] + ".");
}
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\/.*?\//)){
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\/.*?\//)){
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);
//twitter公式1-------------------------------------------------------------------
//フラグ関係はtwitter1に依存
}else if(href.match(/^https?:\/\/pic.twitter.com\/.*$/)){
if(twitter1DB[objLink.href] && twitter1DB[objLink.href] == ""){return;}
name = "twitter1";
twitter1DB[objLink.href] = [];
expandUrl('GET',objLink);
//投稿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\/[\w]+/) && !href.match(/^https?:\/\/p.twimg.com\/.*?\//)){
name = "twitter2";
var commonUrl = href.replace(/^https?/,"https").replace("p.twimg.com","pbs.twimg.com/media").replace(/(.*\/.*):.*$/i,"$1");
var ext = extCheck(href);
if(!href.match(/:orig/)){
src = commonUrl + ".jpg:" + localDB[name +"Size"] + "?." + ext;
href = commonUrl + ".jpg:orig?." + ext;
}
setLink(name);
setThumb(name);
//http://pbs.twimg.com/media/BrHiRU5CMAE_yv-.png#twimg
//twitter公式3
}else if(href.match(/^https?:\/\/pbs.twimg.com\/media\/.*$/)){
name = "twitter3";
var ext = extCheck(href);
function setTwit(num){
var commonUrl = href.replace(/^https?/,"https").replace(/#.*$/,"").replace(/(.*\/.*):.*$/i,"$1");
src = commonUrl + ":" + localDB[name +"Size"] + "?." + ext;
href = commonUrl + ":orig?." + ext;
setLink(name,num);
setThumb(name,num);
}
//twitter1で展開したURL
if(objLink.href != href){
name = "twitter1";
//複数URLだったら
if(twitter1DB[objLink.href] != ""){
for(t=twitter1DB[objLink.href].length -1;t >= 0;t--){
href = twitter1DB[objLink.href][t];
var ext = extCheck(href);
setTwit(t);
}
return; //複数URLはここで終了
}
}
//通常
setTwit();
//http://twitter.com/luv5mj/status/503242246607491072/photo/1
//twitter公式3-------------------------------------------------------------------
//フラグ関係はtwitter3に依存
}else if(href.match(/^https?:\/\/twitter.com\/.*status.*photo.*$/)){
name = "twitter3";
expandUrl('GET',objLink);
//twitter公式3動画のサムネ-------------------------------------------------------------
//フラグ関係はtwitter3に依存
}else if(href.match(/^https?:\/\/pbs.twimg.com\/tweet_video_thumb.*?/)){
name = "twitter3";
var ext = extCheck(href);
src = href + ":" + localDB[name +"Size"] + "?." + ext;
href = href + ":orig?." + ext;
setLink(name);
setThumb(name);
//vine-------------------------------------------------------------
}else if(href.match(/^https?:\/\/vine.co\/v\/./)){
name = "vine";
expandUrl('GET',objLink);
//vineサムネ-----------------------------------------------------------
}else if(href.match(/^https?:\/\/.*vine.co\/.*thumbs\/./)){
name = "vine";
setLink(name);
setThumb(name);
var img = document.getElementById(href).getElementsByTagName("img")[0];
img.setAttribute("style","max-width:" + localDB[name +"Size"] + "px;");
//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\/.*?\/.*$/)){
name = "yfrog";
var commonUrl = href.replace(/^https?/,"https");
src = commonUrl + ":" + localDB[name +"Size"];
href = commonUrl + ":medium";
setLink(name);
setThumb(name);
//http://youtu.be/動画Id
//https://www.youtube.com/watch?feature=player_embedded&v=動画Id
//https://www.youtube.com/watch?v=動画Id
//サムネhttps://img.youtube.com/vi/動画Id/size.jpg
//size: mqdefault – 320×180 , 0 – 480×360 , 1 – 120×90 , 2 – 120×90 , 3 – 120×90
//sizeはmqdefault0と2はデフォルトで使用されるサムネ。1は別の画像、3はさらに別の画像
//youtube--------------------------------------------------------------------------
}else if(href.match(/^https?:\/\/(www|m).youtube.com\/watch.*(\?|&)v=./) || href.match(/^https?:\/\/(youtu.be|y2u.be)\/./)){
var movieId;
name = "youtube";
var commonUrl = "https://img.youtube.com/vi/";
var movieUrl = "https://www.youtube.com/embed/";
if(href.match(/^https?:\/\/(youtu.be|y2u.be)/)){
//短縮URLを簡易的に展開
if(localDB["AllThumbsAndLinksSize"]){
movieId = href.replace(/^https?:\/\/(youtu.be|y2u.be)\//,"");
href = "https://www.youtube.com/watch?v=" + movieId;
allLinks.snapshotItem(i).setAttribute("data-expanded-url",href);
}
}else{
movieId = href.replace(/.*(\?|&)v=/,"");
}
movieId = movieId.replace(/(\?|&).*/,"").replace(/#.*/,"").replace(/\/$/,"");
src = commonUrl + movieId + "/" + localDB[name +"Size"] + ".jpg";
href = commonUrl + movieId + "/0.jpg";
setLink(name);
setThumb(name);
addMovie(name,objLink,href,movieUrl + movieId);
//その他-------------------------------------------------------------------------
}else{
//拡張子ありのURLのサムネだけ追加-------------------------------------
var comma = href.slice(-5).indexOf(".");
fileType = ""; //拡張子
if(comma > -1 && comma < 2){
//その他の画像URLのサムネ追加
name = "otherPic";
if(localDB[name + "Thumb"]){
fileType = href.replace(/.*\./,"");
//画像の拡張子だったらサムネ追加
fileExt.forEach(function(x){
if(x == fileType){ setThumb(name); }
});
}
//動画の拡張子だったら・・・
}
}
}//for文ここまで
//保存用のリンク追加----------------------------------------------------------------------------------
function setLink(name,num){
//ユーザー設定で追加しないなら終了
if(localDB["AllThumbsAndLinksLink"] == false || localDB[name +"Link"] == false){
return;
}
var className = '';
if(name == "twitgoo"){
var className = 'twitgooText';
}
var ele = document.createElement("div");
var strLinkText = '<a class="' + className + '" target="_blank" href="' + href + '" >'
+'<img src=\'chrome://browser/skin/tabbrowser/loading.png\'>now loading'
//リンク切れ確認用imgタグ
+ '<img src="' + src + '" onError="function reloadimg(e,p,timer){setTimeout( '
//画像読み込み失敗でリロードをかける
+ 'function(){ '
+ 'if(e.src.match(/\\?dummy=/)){ e.src = e.src.replace(/dummy=/,\'dummy=d\');'
//1回ごとに拡張子を変更してみる(ow.lyに有効)
+ 'if(e.src.match(/.jpg/)){ e.src = e.src.replace(/.jpg/,\'.png\');p.href=p.href.replace(/.jpg/,\'.png\');'
+ '}else if(e.src.match(/.jpg/)){ e.src = e.src.replace(/.png/,\'.jpg\');p.href=p.href.replace(/.png/,\'.jpg\'); }'
+ '}else{ e.src = e.src + \'?dummy=d\' }'
+ '},timer); }'
//5回試行でも読み込み失敗ならdead link
+ 'if(!this.src.match(\'dummy=ddddd\')){reloadimg(this,this.parentNode,~~(Math.random()*(5000-2000)+2000));'
+ '}else{this.parentNode.style=\'font-size:12px\';'
+ 'this.parentNode.innerHTML=\'' + strIcon
+ '<a href=' + href + '>dead link</a>\'}" '
+ 'onload= "this.innerHTML=\'\';this.parentNode.innerHTML=\'' + strIcon + 'Save Image As...\';"'
+ 'Style="max-width:0px;max-height:0px;"></a><br>';
//サムネを追加しない場合改行追加
if(localDB["AllThumbsAndLinksThumb"] == false || localDB[name + "Thumb"] == false){
//複数画像指定じゃない。または複数画像指定の1枚目だったら改行追加
if(!num || num && num == 0){objLink.innerHTML = "<br>" + objLink.innerHTML; strLinkText = "<br>" + strLinkText;}
}
objLink.insertAdjacentHTML(insertWhere, strLinkText);
objLink.setAttribute("ToT_Link","added");
objLink.removeAttribute("ToT_URL");
}//リンク追加ここまで
//サムネ追加----------------------------------------------------------------------------------
function setThumb(name,num){
//ユーザー設定で追加しないなら終了
if(localDB["AllThumbsAndLinksThumb"] == false || localDB[name +"Thumb"] == false){
return;
}
var strMW = "510"; //max-width
var className = "", resolvedUrl = "";
//画像クリックで出るポップアップウィンドウ内
if(objLink.parentNode.parentNode.parentNode.className.match(/simple-tweet/)){
strMW = "400";
}
//imgurのgifを動かすための対応
if(name == "imgur" && fileType.match(/gif/i)){
var imgurSize = localDB[name +"Size"];
if(imgurSize == "s") strMW = "90";
if(imgurSize == "m") strMW = "320";
//droplrのgifを動かすための対応
}else if(name = "droplr"){
if(localDB[name +"Size"] == "custom") strMW = "100";
//サムネのピンボケ対策などサイズ指定
}else if(name == "otherPic" && localDB[name + "Size"] == "thumb"){
strMW = "150";
}
//クラス名
if(objLink.className){
//className = ' class="' + objLink.className + '"';
className = ' class="media media-thumbnail twitter-timeline-link is-preview"';
}
var strThumbText = '<a id=' + href + className + resolvedUrl + ' href=' + href + ' data-resolved-url-large=' + href
+ ' Style="padding-right:5px;" ToT_Thumb=added onclick="return false;" >'
+ '<img src="' + src + '" onerror="function reloadimg(e,p,timer){setTimeout( '
//画像読み込み失敗でリロードをかける
+ 'function(){ '
+ 'if(e.src.match(/\\?dummy=/)){ e.src = e.src.replace(/dummy=/,\'dummy=d\');'
//twitter公式で読み込み失敗時thumb自体がない?→サムネ指定削除
+ 'if(e.src.match(/pbs.twimg.com/)){ p.href = p.href.replace(/:large.*/,\'\');'
+ 'e.src = e.src.replace(/(.*):.*/i,\'$1\');'
+ 'onload();}'
//1回ごとに拡張子を変更してみる(ow.lyに有効)
+ 'if(e.src.match(/.jpg/)){ e.src = e.src.replace(/.jpg/,\'.png\');p.href=p.href.replace(/.jpg/,\'.png\');'
+ '}else if(e.src.match(/.png/)){ e.src = e.src.replace(/.png/,\'.jpg\');p.href=p.href.replace(/.png/,\'.jpg\'); }'
//1回ごとにサムネサイズ変更(movapic)
+ 'if(e.src.match(/\\/t_/)){ e.src = e.src.replace(/\\/t_/,\'/s_\');'
+ '}else if(e.src.match(/\\/s_/)){ e.src = e.src.replace(/\\/s_/,\'/t_\'); }'
+ '}else{ e.src = e.src + \'?dummy=d\'; }'
+ '},timer); }'
//5回試行でも読み込み失敗ならdead link
+ 'if(!this.src.match(\'dummy=ddddd\')){reloadimg(this,this.parentNode,~~(Math.random()*(5000-2000)+2000));'
+ '}else if(this.src.match(/dummy=ddddd$/)){this.parentNode.style=\'font-size:12px\';'
+ 'this.insertAdjacentHTML(\'afterend\','
+ '\'' + strIcon + '<a href=' + href + '>dead link</a>\''
+ ');'
+ 'this.setAttribute(\'onerror\',\'\');'
+ '}" Style="max-width:' + strMW + 'px;"></a>';
//複数画像の時の改行
if(num || num == 0){
if(num == 0){ strThumbText = "<br>" + strThumbText; objLink.innerHTML = "<br>" + objLink.innerHTML; }
//通常
}else{
strThumbText = "<br>" + strThumbText + "<br>"
//元のリンクも改行
objLink.innerHTML = "<br>" + objLink.innerHTML;
}
try{
//ユーザーのツイートページだった場合のサムネ
if(!location.href.match(/https?:\/\/twitter.com\/search\?/)
&& objLink.parentNode.parentNode && objLink.parentNode.parentNode.className == "TwitterPhoto-container"){
if(objLink.innerHTML.match(/<img/i)){
//class"TwitterPhoto-link media-thumbnail twitter-timeline-link"の中に入れる
insertWhere = "afterbegin";
objLink.innerHTML = "";
//一個上の要素のcssが邪魔なのでclass名変更
objLink.parentNode.className = "ToT_changed:" + objLink.parentNode.className;
}
}
//追加
objLink.insertAdjacentHTML(insertWhere, strThumbText);
objLink.setAttribute("ToT_Thumb","added");
//削除
if(objLink.className=="media media-thumbnail twitter-timeline-link is-preview")objLink.innerHTML ="";
delDef(objLink);
}catch(e){
GM_log("main_end:" + e);
}
objLink.removeAttribute("ToT_URL");
}//サムネ追加ここまで
}//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(){openClose()}, true);
setBtn.setAttribute("Style",setPos);
}
//画像クリックで設定画面の開く閉じる切り替え
function openClose(){
if(document.evaluate("//iframe[@id='GM_config']",document,null,9,null).singleNodeValue){
GM_config.close();
}else{
GM_config.open();
}
}
//設定画面(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_doc = cfg_Window.contentDocument;
var cfg_body = cfg_doc.getElementsByTagName("body")[0];
//youtubeQualityの設定-----------------
var cfg_youtubeQL = cfg_doc.getElementById("field_youtubeQualityLink");
var cfg_youtubeQT = cfg_doc.getElementById("field_youtubeQualityThumb");
cfg_youtubeQT.parentNode.insertAdjacentHTML('afterend', "<label style=background:lightgray; class=field_label>youtubecenterなどの設定を優先します。"
+ "<br>\"youtubecenter and Others\" settings is high Priority,<br>more than this.</label>");
//youtubeQualityの設定で2つ非表示
cfg_youtubeQL.parentNode.setAttribute("style","display:none;");
cfg_youtubeQT.parentNode.setAttribute("style","display:none;");
//youtubeQualityの設定ここまで-----------------
//閉じる
cfgClose(document);
cfgClose(cfg_body);
//ESC押したら設定画面閉じる
function cfgClose(doc){
try{
doc.onkeydown = function(evt){
if (evt){
var kc = evt.keyCode;
}else{
var kc = event.keyCode;
}
//GM_log(kc);
if(kc!=27){ return; }
GM_config.close();
}
}catch(e){
GM_log("escClose:"+e);
}
}//cfgCloseここまで
//説明書き
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", "");
//各サムネ設定の配置指定--------------------------------------------------
//共通
var cssCommon = '#buttons_holder{ position:fixed; right:10px; bottom:8px;}';
//解像度低い場合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,cssCommon);
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 + "Link") != undefined && GM_config.get(name + "Link") != 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,大きいサイズにするとはみ出るので最大510pxにしています。\r\n'
+ ' max-width 510px,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 && !node.hasAttribute("class")){return;}
//検索結果
var newSearch = document.evaluate('.//div[@class="new-tweets-bar js-new-tweets-bar "]', node, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
try{
var nClass = node.getAttribute("class");
}catch(e){
switch( e.name ){
case 'TypeError':
// GM_log("NewTweet-TypeError:" + e);
return;
default:
GM_log("NewTweet-Error:" + e);
}
}
if(nClass != "Grid" //ユーザーページの更新以外
&& newSearch.snapshotItem(0) == null){ //検索やタイムラインの更新以外
return;
}else{
audio.play();
// alert(newSearch.snapshotItem(0).innerHTML);
}
}
//url展開
function expandUrl(type,obj,size){
var url = obj.href;
if(obj.hasAttribute("ToT_URL") && obj.getAttribute("ToT_URL").match(/^http/)){
url = obj.getAttribute("ToT_URL");
obj.setAttribute("ToT_URL","NowLoading:" + url);
}
//GM_xmlhttpRequestが非同期のため、その対応
if(expDB[url]){ return;
}else{ expDB[url] = "loading"; }
GM_xmlhttpRequest({
method: type,
url: url,
onload: function (res) {
try{
//短縮URLの展開用
if(type == "HEAD"){
//Flickr短縮URL
if(url.match(/^https?:\/\/flic.kr\/(p|s)\/.*/)){
//GM_log(res.finalUrl);
obj.setAttribute("data-expanded-url",res.finalUrl.replace(/\?.*/,""));
//Fickr画像URLから元のURL取得
}else if(url.match(/^https:\/\/flickr.com\/photo.gne\?id=/)){
//何故かURLが取得できずにyahooにログインを求められるパターンがあるので元URLが取得できない
if(res.finalUrl.match(/^https?:\/\/login.yahoo.com\/config\/login/)){
obj.setAttribute("ToT_URL","Error:" + url);
}else{
obj.setAttribute("ToT_URL",res.finalUrl.replace(/\?.*/,""));
}
//tumblr短縮URL
}else if(url.match(/^https?:\/\/(www.)?tu?mblr.com?\/[a-zA-Z0-9].*$/)){
obj.setAttribute("data-expanded-url",res.finalUrl.replace(/#.*/,""));
}
//メインに戻す
main(obj);
return;
//画像URLの取得用
}else if(type == "GET"){
//twitter1
if(!obj.hasAttribute("ToT_URL") && url.match(/^https?:\/\/pic.twitter.com/)){
obj.setAttribute("ToT_URL",res.responseText.replace(/.*\;URL\=(http.*?)\"\>.*/i,"$1"));
expandUrl('GET',obj);
return;
}
//最初からこのURLの場合と↑でtwitter1の展開した後さらに展開して画像URL取得の場合がある
if(url.match(/^https?:\/\/twitter.com.*\/photo\//)){
//GM_log(res.responseText);
var strTmp;
//動画埋め込みの場合
if(res.responseText.match(/<source video-src="http.*"/)){
name = "twitter3";
var strTmp = res.responseText.match(/<img src="(https?:\/\/pbs.twimg.com\/tweet_video_thumb.*?)"/)[1];
var movieUrl = res.responseText.match(/<source video-src="(https?:\/\/pbs.twimg.com\/tweet_video.*?)"/)[1];
obj.setAttribute("ToT_URL",strTmp);
main(obj);
addMovie(name,obj,strTmp + "media?size=l",movieUrl);
return;
}
var num = res.responseText.match(/<div class="multi-photos photos-(.*?)">/);
if(num){ num = num[1]} //複数枚なら
var array = res.responseText.match(/<img src="(https?:\/\/pbs.twimg.com\/media.*?)"/g);
var reg = new RegExp('<img src="(.*)"$');
strTmp = array[0].replace(reg,"$1");
//複数画像対応
if(array.length>1){
for(t=0;t < num;t++){
twitter1DB[obj.href].push(array[t].replace(reg,"$1"));
}
}
obj.setAttribute("ToT_URL",strTmp);
main(obj);
return;
}
//Flickr(メイン関数→サムネ入手後→オリジナル入手→メイン関数へ)
if(obj.hasAttribute("ToT_URL") && url.match(/^https?:\/\/(www.)?flickr.com\/photos\//)){
//サムネ側のURL
if(size || size == ""){
var tmpReg = new RegExp('<img src="(https?:\/\/.*?static.?flickr.*?' + size + '..*)">');
flickrSrcDB[obj.href] = res.responseText.match(tmpReg)[1];
//オリジナルサイズを取得へ
obj.setAttribute("ToT_URL",url.replace(/\/sizes\/.*/,"\/sizes/o/"));
expandUrl('GET',obj);
return;
//オリジナルサイズ側のURL
}else if(url.match(/\/sizes\/o\//)){
var tsize = "o";
//オリジナルサイズがoじゃなかったら変更
if(!res.finalUrl.match(/sizes\/o\/?$/)){
tsize = res.finalUrl.replace(/.*sizes\/(.*?)\/$/i,"$1");
tsize = flickrSize(tsize);
}
var reg = new RegExp('<img src="(https?:\/\/.*?static.?flickr.*?' + tsize + '..*?)">');
obj.setAttribute("ToT_URL",res.responseText.match(reg)[1]);
main(obj);
return;
}
}
//imgur画像URL
if(url.match(/^https?:\/\/.*imgur.com/)){
obj.setAttribute("ToT_URL",res.responseText.match(/<link rel="image_src" href="(https?:\/\/i.imgur.com\/.*?)"\/>/)[1]);
main(obj);
return;
}
//instagram動画チェック
if(url.match(/^https?:\/\/(i.)?(i|I)nstagr(am.com|.am)\/p\/.*?\//) && !url.match(/^https?:\/\/instagr(am.com|.am)\/p\/.*?\/.*\//)){
name = "instagram";
//動画URLだったら埋め込む
if(res.responseText.match(/<meta property="og:video" content="http/)){
var movieUrl = res.responseText.match(/<meta property="og:video" content="(http.*?)"/)[1];
addMovie(name,obj,url,movieUrl);
return;
}
}
//携帯百景movapic
if(url.match(/^https?:\/\/movapic.com\/.*?\/pic\/.*$/)){
obj.setAttribute("ToT_URL",res.responseText.match(/<img class="image" src="(https?:\/\/image.movapic.com\/pic\/.*?..*?)"\/>/)[1]);
main(obj);
return;
}
//tumblr
if(url.match(/^http:\/\/[\w\-]+.tumblr.com\/image\/[0-9]+.*$/)){
//オリジナルサイズ
var tempUrl = res.responseText.match(/data-src="(http:\/\/\d+.media.tumblr.com\/(.*?\/)?.*_\d+..*)" data-height/)[1];
obj.setAttribute("ToT_URL",tempUrl);
main(obj);
return;
}
//vine
if(url.match(/^https?:\/\/vine.co\/v\/./)){
try{
var tmpUrl = res.responseText.match(/<meta property="twitter:image" content="(http.*?)\?versionId=/)[1];
var movieUrl = res.responseText.match(/<meta property="twitter:player:stream" content="(http.*?)\?versionId=/)[1];
}catch(e){
//動画削除済み
obj.insertAdjacentHTML('afterend', strIcon + '<a target="_blank" style=font-size:12px; href=' + url + '>dead link</a>');
return;
}
obj.setAttribute("ToT_URL",tmpUrl);
main(obj);
addMovie(name,obj,tmpUrl,movieUrl);
}
}
}catch(e){
GM_log(e);
return;
}
}//onloadここまで
});
}
//ムービー追加
function addMovie(name,obj,img,url){
try{
//サムネ追加設定
if(localDB["AllThumbsAndLinksThumb"] == false || localDB[name +"Thumb"] == false){
return;
}
var srcTxt = "";
var cssTxt = "";
//iframeの読込先指定(srcはURLから、srcdocは直接ソースから)
//youtube
if(name == "youtube"){ srcTxt = 'src=' + url + '?vq=' + localDB["youtubeQualitySize"] + ' frameborder=0 allowfullscreen ';
//その他
}else{
srcTxt = 'srcdoc=\\\''
+'<video class=ToT_video controls poster=' + img + ' width=400 height=300>'
+'<source src=' + url + '>not support video tag</video>'
+'\\\' '
}
//追加テキスト
var movie = '<a onclick="'
+'function addFrame(o){'
+'var txt='
+'\'<iframe seamless width=450 height=350 '
+ srcTxt
+'></iframe>\''
+';'
+'o.insertAdjacentHTML(\'afterend\',txt);'
+'o.parentNode.removeChild(o);'
+'}'
+'addFrame(this);return false;" ' + cssTxt + ' href="' + url + '">' + strIcon + 'add movie</a>';
obj.insertAdjacentHTML('afterend', movie);
delDef(obj);
}catch(e){
GM_log("addMovie:"+ e);
}
}
//twitter側の追加サムネ削除
function delDef(obj){
//twitterが追加するサムネの表示設定
if(localDB["flgDefPic"] == false){
//2個上の要素(コメント1個分)
var content = obj.parentNode.parentNode;
var expand = content.getElementsByClassName("expanded-content js-tweet-details-dropdown"); //下の入れ子(ない場合もある)
var photo = content.getElementsByClassName("card2 js-media-container"); //twitter側画像展開
var card = content.getElementsByClassName("cards-base cards-multimedia"); //twitter側画像展開その2
var user = content.getElementsByClassName("TwitterPhoto js-media-container"); //twitter側画像(@タイムライン)
var multi = content.getElementsByClassName("TwitterMultiPhoto js-media-container"); //twitter側複数画像(@タイムライン)
var thumb = content.getElementsByClassName("media media-thumbnail twitter-timeline-link media-forward is-preview"); //twitter側サムネ画像)
//要素削除
var delPic = function(objTmp){
if(objTmp[0]){ objTmp[0].parentNode.removeChild(objTmp[0]); }
};
delPic(expand);
delPic(photo);
delPic(card);
delPic(user);
delPic(multi);
delPic(thumb);
var view = content.getElementsByClassName("details with-icn js-details"); //画像を表示するリンク
if(view[0]){ view[0].className="ToTChanged_details with-icn js-details"; }
}
}
function extCheck(url){
var tmp = "";
//画像の拡張子だったらその拡張子のまま
fileExt.forEach(function(x){
if(url.match(x)){tmp = x;}
});
if(tmp != ""){ return tmp;}
return "jpg";
}
//flickrのサイズ修正
function flickrSize(size){
if(size == "sq"){ size = "_s";
}else if(size == "s"){ size = "_m";
}else if(size == "m"){ size = "";
}else if(size == "l"){ size = "_b";
}else{ size = "_" + size;
}
return size;
}
//ユーザー関数ここまで============================================================================
//引用開始===================================================================================
//==============================================================
//すでに組まれている方がいたのでソースを拝借(少し書き換え)
//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を使って何かする
}
*/
//引用ここまで===============================================================================
})();