NicoMylist poster with XML-RPC

By azu_re Last update Jun 27, 2011 — Installed 211 times.

There are 7 previous versions of this script.

Add Syntax Highlighting (this will take a few seconds, probably freezing your browser while it works)

// ==UserScript==
// @name           NicoMylist poster with XML-RPC
// @namespace      http://efcl.info/
// @include        http://www.nicovideo.jp/mylist*
// @require        https://raw.github.com/gist/310354/b2adc95e35f53cfb8162490b938639ab66db5ea9/GM_config.js
// ==/UserScript==
// http://d.hatena.ne.jp/jimo1001/20090601/1243782686
var ShortcutKey = function() {
    this.list = [];
    this.init();
}
ShortcutKey.prototype.keys = {
    8: 'BS',
    9: 'TAB',
    10: 'RET',
    13: 'RET',
    32: 'SPC',
    27: 'ESC',
    33: 'PageUp',
    34: 'PageDown',
    35: 'End',
    36: 'Home',
    37: 'Left',
    38: 'Up',
    39: 'Right',
    40: 'Down',
    45: 'Insert',
    46: 'Delete',
    112: 'F1',
    113: 'F2',
    114: 'F3',
    115: 'F4',
    116: 'F5',
    117: 'F6',
    118: 'F7',
    119: 'F8',
    120: 'F9',
    121: 'F10',
    122: 'F11',
    123: 'F12'
}
ShortcutKey.prototype.skeys = {
    8: 'BS',
    10: 'RET',
    13: 'RET',
    32: 'SPC'
}
ShortcutKey.prototype.mkeys = {
    'altKey' : 'A',
    'ctrlKey' : 'C',
    'metaKey' : 'M',
    'shiftKey' : 'S'
}
ShortcutKey.prototype.init = function() {
    var self = this;
    window.addEventListener('keydown', function(evt) {
        var key = self.get(evt);
        self.list.forEach(function(a) {
            if (a.key == key && (a.element == evt.target || a.element == evt.view)) {
                // 				console.log(a.key +"=="+ key);
                a.func();
            }
        });
    }, false);
}
ShortcutKey.prototype.add = function(elm, key, func) {
    this.list.push(
    {
        'element' : elm,
        'key' : key,
        'func' : func
    }
            );
}
ShortcutKey.prototype.get = function(evt) {
    var key = [], k = '';
    for (mk in this.mkeys) {
        if (evt[mk])
            key.push(this.mkeys[mk]);
    }
    if (evt.which) {
        k = this.keys[evt.which] || String.fromCharCode(evt.which).toLowerCase();
        key.push(key.length ? '-' + k : k);
    } else if (evt.keyCode) {
        k = this.keys[evt.keyCode];
        key.push(key.length ? '-' + k : k);
    }
    return key.join("");
}
/* ショートカット */
var shortcut = new ShortcutKey();
GM_config.init('Configuration for Post', {
    endPoint:    { label: 'EndPoint:', type: 'text' , "default": 'http://' },
    blogid:    { label: 'Blogid:', type: 'text' , "default": '' },
    username:    { label: 'username:', type: 'text' , "default": '' },
    password:    { label: 'password:', type: 'text' , "default": '' },
    titlePre:    { label: '投稿title prefix:', type: 'text' , "default": '' },
    category:    { label: '投稿category:', type: 'text' , "default": '' },
    ShortCutKey:    { label: 'ShortcutKey:', type: 'text' , "default": 'CS-RET' }
}, "#config_header {font-size:16pt !important;} .config_var {margin:5px 0 5px 20% !important;} #header {margin-bottom:30px !important;} .indent40 {margin-left:20% !important;}", // to add your CSS - replace this with configStyle
{
    open: function() {
        var iframe = document.getElementById("GM_config");
        iframe.contentDocument.getElementById("field_ShortCutKey").addEventListener('keydown', function(evt) {
            evt.preventDefault();
            this.value = shortcut.get(evt);
        }, false);
    },
    save: function() {

    } // reload the page when configuration was changed
});
GM_registerMenuCommand('Post Setting', GM_config.open);

/* 投稿先のメタ情報 */
var metaBlog = {
    "endPoint" : GM_config.get("endPoint"),
    "blogid"   : GM_config.get("blogid"),
    "username" : GM_config.get("username"), //空だとblogidを使用
    "password" : GM_config.get("password")
}

var XMLRPC = (function() {
    this.initialize.apply(this, arguments);
});
XMLRPC.prototype = {
    /*
     * @arg
     {
     "endPoint": "endPoint",
     "blogid"   : "blogid",
     "username" : "username",//空だとblogidを使用
     "password" : "password"
     }
     */
    initialize : function(arg) { //引数は{}オブジェクト
        this.endPoint = arg.endPoint;
        this.blogid = arg.blogid;
        this.username = (arg.username) ? arg.username : arg.blogid;
        this.password = arg.password;
    },
    /* *
     * @title 記事タイトル
     * @desc 記事内容
     * @tags タグ(カンマ区切り)
     * @callback 更新成功時のコールバック関数
     */
    post : function (title, desc, categories, tags, callback) {
        var postURI = this.endPoint;
        this.tags = (tags.length == 0) ? "" : tags.join(",");
        var XMLbody = '<?xml version="1.0"?>\n';
        XMLbody += this.template(title, desc, this.tags);
        //		console.info(XMLbody);
        GM_xmlhttpRequest({
            method : "POST",
            headers : {
                'Content-type' : 'text/xml'
            },
            url : postURI,
            data : this.template(title, desc, categories, tags),
            onload : callback,
        })
    },
    template : function (title, desc, categories, tags) {
        var request = <methodCall>
            <methodName>metaWeblog.newPost</methodName>
            <params>
                <param>
                    <value>
                        <string>{this.blogid}</string>
                    </value>
                </param>
                <param>
                    <value>
                        <string>{this.username}</string>
                    </value>
                </param>
                <param>
                    <value>
                        <string>{this.password}</string>
                    </value>
                </param>
                <param>
                    <value>
                        <struct>
                            <member>
                                <name>title</name>
                                <value>
                                    <string>{title}</string>
                                </value>
                            </member>
                            <member>
                                <name>description</name>
                                <value>
                                    <string>{desc}</string>
                                </value>
                            </member>
                            <member>
                                <name>categories</name>
                                <value>
                                    <array>
                                        <data>
                                            <value>{categories}</value>
                                        </data>
                                    </array>
                                </value>
                            </member>
                            <member>
                                <name>mt_keywords</name>
                                <value>
                                    <string>{tags}</string>
                                </value>
                            </member>
                            <member>
                                <name>mt_allow_comments</name>
                                <value>
                                    <boolean>1</boolean>
                                </value>
                            </member>
                            <member>
                                <name>mt_convert_breaks</name>
                                <value>
                                    <string>0</string>
                                </value>
                            </member>
                        </struct>
                    </value>
                </param>
                <param>
                    <value>
                        <boolean>1</boolean>
                    </value>
                </param>
            </params>
        </methodCall>;
        return request.toString();
    }
}
/*
 * Draggable
 *
 * @website http://clonedoppelganger.net/
 * @version 0.0.2
 */
/**
 * Constructor
 * @param {String|Element} element - element id or element object
 */
var Draggable = function(element) {
    this.initialize(element);
}

/**
 * remove EventListeners
 */
Draggable.prototype.destroy = function() {
    this.detach(this.element, "mousedown", this.observers["mousedown"]);
    this.detach(this.html, "mouseup", this.observers["mouseup"]);
    this.detach(this.html, "mousemove", this.observers["mousemove"]);
}

Draggable.prototype.initialize = function(element) {
    this.isIE = navigator.appVersion.lastIndexOf("MSIE") > 0;
    this.isFF = navigator.userAgent.toLowerCase().indexOf("firefox") > 0;
    this.html = document.getElementsByTagName("html").item(0);
    if (typeof element == "string") {
        this.element = document.getElementById(element);
    } else {
        this.element = element;
    }
    this.style = this.element.style;
    this.thisBaseX;
    this.thisBaseY;
    this.pageBaseX;
    this.pageBaseY;
    this.scrollBaseY;
    this.isMoving = false;
    this.observers = {};
    var self = this;
    // Mousedown
    this.observers["mousedown"] = this.observe(this.element.firstChild, "mousedown", function(event) {
        if (self.isMoving) return;
        event = event || window.event;
        //self.disableSelect(event);
        var position = self.getPosition();
        self.thisBaseX = position["x"];
        self.thisBaseY = position["y"];
        self.pageBaseX = event.pageX || event.clientX;
        self.pageBaseY = event.pageY || event.clientY;
        if (self.isIE) self.scrollBaseY = document.body.scrollTop;
        self.isMoving = true;
    });
    // Mousemove
    this.observers["mousemove"] = this.observe(this.html, "mousemove", function(event) {
        if (!self.isMoving) return;
        event = event || window.event;
        var x = (event.pageX || event.clientX) - self.pageBaseX + self.thisBaseX;
        var y = (event.pageY || event.clientY) - self.pageBaseY + self.thisBaseY;
        if (self.isIE) y += (parseInt(document.body.scrollTop) - self.scrollBaseY);
        self.setPosition(x, y);
    });
    // Mouseup
    this.observers["mouseup"] = this.observe(this.html, "mouseup", function(event) {
        if (!self.isMoving) return;
        self.enableSelect();
        self.isMoving = false;
    });
}

Draggable.prototype.observe = function(element, name, observer) {
    if (element.addEventListener) {
        element.addEventListener(name, observer, true);
    } else if (element.attachEvent) {
        element.attachEvent("on" + name, observer);
    }
    return observer;
}

Draggable.prototype.detach = function(element, name, observer) {
    if (element.removeEventListener) {
        element.removeEventListener(name, observer, true);
    } else if (element.detachEvent) {
        try {
            element.detachEvent("on" + name, observer);
        } catch (e) {
        }
    }
}

Draggable.prototype.setPosition = function(x, y) {
    this.style.left = x + "px";
    this.style.top = y + "px";
}

Draggable.prototype.getPosition = function() {
    var x, y;
    // First you acquire from css style information.
    if (this.style.top == "" || this.style.left == "") {
        if (this.element.currentStyle) {
            x = this.element.currentStyle["left"];
            y = this.element.currentStyle["top"];
        } else {
            var computedStyle = document.defaultView.getComputedStyle(this.element, null);
            x = computedStyle["left"];
            y = computedStyle["top"];
        }
    } else {
        x = this.style.left;
        y = this.style.top;
    }
    return {"x": parseInt(x.replace("px", "")) || 0, "y": parseInt(y.replace("px", "")) || 0};
}

Draggable.prototype.disableSelect = function(event) {
    if (this.isIE) {
        document.getElementsByTagName("body").item(0).onselectstart = function(e) {
            return false
        };
    } else {
        try {
            event.preventDefault();
        } catch(e) {
        }
    }
}

Draggable.prototype.enableSelect = function() {
    if (this.isIE) document.getElementsByTagName("body").item(0).onselectstart = "";
}

/**
 * ポップアップを作成する
 * @title {str} ウィンドウタイトル
 * @defaultInput {str} テキストエリアのデフォルト値
 * @callback {function} callback関数 引数に入力した文字列
 * */
function createPopup(title, defaultInput, defaultTags, callback, altLead) {
    if (typeof altLead == 'undefined') altLead = true;
    var GM_popup_container = document.createElement("div");
    GM_popup_container.id = "GM_popup_container";
    GM_popup_container.class = "ui-draggable";
    var GM_popup_title = document.createElement("input");
    GM_popup_title.id = "GM_popup_title";
    GM_popup_title.value = title;
    var GM_popup_content = document.createElement("div");
    GM_popup_content.id = "GM_popup_content";
    GM_popup_content.setAttribute("class", "comfirm");
    var GM_popup_message = document.createElement("div");
    GM_popup_message.id = "GM_popup_message";
    GM_popup_message.textContent = "コメントの入力"
    var GM_popup_br = document.createElement("br");
    var GM_popup_prompt = document.createElement("textarea");
    GM_popup_prompt.id = "GM_popup_prompt";
    if (altLead && defaultInput) {// 先頭にカーソル
        GM_popup_prompt.value = defaultInput;
    } else {
        GM_popup_prompt.value = defaultInput + " ";
    }
    var GM_popup_tags = document.createElement("input");
    GM_popup_tags.type = "text";
    GM_popup_tags.id = "GM_popup_tags";
    GM_popup_tags.value = defaultTags || "";
    var GM_popup_panel = document.createElement("div");
    GM_popup_panel.id = "GM_popup_panel";
    var GM_popup_ok = document.createElement("input");
    GM_popup_ok.type = "Button"
    GM_popup_ok.id = "GM_popup_ok";
    GM_popup_ok.value = " OK "
    var GM_popup_cancel = document.createElement("input");
    GM_popup_cancel.type = "Button"
    GM_popup_cancel.id = "GM_popup_cancel";
    GM_popup_cancel.value = " Cancel ";
    var GM_popup_counter = document.createElement("p");
    GM_popup_counter.id = "GM_popup_counter";
    GM_popup_counter.textContent = 140 - defaultInput.length;
    GM_popup_ok.addEventListener("click", function() {
        this.removeEventListener("click", arguments.callee, false);
        document.body.removeChild(GM_popup_container);
        callback(GM_popup_title.value, GM_popup_prompt.value, GM_popup_tags.value);
    }, false);
    GM_popup_cancel.addEventListener("click", function() {
        this.removeEventListener("click", arguments.callee, false);
        document.body.removeChild(GM_popup_container);
        callback(false);
    }, false);
    GM_popup_prompt.addEventListener("keypress", function(e) {
        var c = (e.ctrlKey)
        var v = (e.keyCode == 13)
        if (c && v) {
            this.removeEventListener("keypress", arguments.callee, false);
            document.body.removeChild(GM_popup_container);
            callback(GM_popup_title.value, GM_popup_prompt.value, GM_popup_tags.value);
        } else {
            var counter = 140 - GM_popup_prompt.value.length;
            GM_popup_counter.textContent = counter;
        }
    }, false);

    GM_popup_panel.appendChild(GM_popup_ok);
    GM_popup_panel.appendChild(GM_popup_cancel);
    GM_popup_message.appendChild(GM_popup_br);
    GM_popup_message.appendChild(GM_popup_prompt);
    GM_popup_message.appendChild(GM_popup_tags);
    GM_popup_message.appendChild(GM_popup_counter);
    GM_popup_content.appendChild(GM_popup_message);
    GM_popup_content.appendChild(GM_popup_panel);
    GM_popup_container.appendChild(GM_popup_title);
    GM_popup_container.appendChild(GM_popup_content);

    document.body.appendChild(GM_popup_container);
    // フォーカスを先頭に
    var d = document.getElementById("GM_popup_prompt");
    setTimeout(function() {
        d.focus();
        if (altLead) {// 先頭にカーソル
            d.setSelectionRange(0, 0);
        } else {
            d.setSelectionRange(GM_popup_prompt.value.length, GM_popup_prompt.value.length);
        }
    }, 100)
}

GM_addStyle(String(<>
    <![CDATA[
	#GM_popup_container {
		padding: 0pt;
		position: fixed;
		overflow:auto;
		z-index: 99999;
		margin: 0pt;
		top: 330px;
		left: 450px;
		font-family: Arial, sans-serif;
		font-size: small!important;
		min-width: 300px; /* Dialog will be no smaller than this */
		width: 450px; /* Dialog will wrap after this width */
		min-height: 100px; /* Dialog will be no smaller than this */
		height:240px; /* Dialog will wrap after this width */
		background: #FFF;
		border: solid 5px #999;
		color: #000;
		-moz-border-radius: 5px;
		-webkit-border-radius: 5px;
		border-radius: 5px;
	}

	#GM_popup_title {
		width: 100%; /* Dialog will wrap after this width */
		font-size: medium;
		font-weight: bold;
		text-align: center;
		line-height: 1.75em;
		color: #666;
		background: #CCC url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAXCAYAAADDcYV1AAAA6klEQVQYlW3I23KCMBhF4f/9n60Y5BBTBEIIhxBF9AlWL2SclunFN2vPltfrxZH8ez6fT45ke2xs21+yPh6s68qn64rc73eOJN4iMUZuuxgjEpaFJQSWEAghsCwBmaaJeZ6Z5nnvhIzjyLAbh4FhGBHfe/re4/se73u894hzjq7rcK7DdQ7nHNJai21bbGtp2xZrLVLXDU1dU9cNdfMm1fVKVVV8WlWIMQZjDN97zbdB9EVz0Rq9u2iNlGVJUZQURfGp5HlOnmXkWUaWvbecz2eORCmFShVKpaRpilIKOZ1OHEmSJHwlCckvP7cioIs4K9DKAAAAAElFTkSuQmCC") top repeat-x;
		border: solid 0px #FFF;
		border-bottom: solid 1px #999;
		cursor: move;
		padding: 0em;
		margin: 0em;
	}

	#GM_popup_content {
		width: 95%;
		padding: 0.5em 1em 0.5em 0;
		margin: 0em;
	}


	#GM_popup_content.comfirm {
		background: 12px 12px no-repeat url("data:image/png;base64,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");
	}
	#GM_popup_message {
		width: 95%;
		font-size: small!important;
		text-align: center;
		padding-left: 24px;
	}

	#GM_popup_counter{
		position: absolute;
		margin: 3pt;
		button: 10px;
		left: 10px;
		font-size :large;
		color : #AAAAAA;
		font-family:'Helvetica Neue','Helvetica','Arial',sans-serif;
		line-height :1.9em
	}
	#GM_popup_panel {
		text-align: center;
		margin: 0.5em 0em 0em 1em;
	}
	#GM_popup_prompt{
      height:100px;
	  width: 90%;
	  margin-left: 32px;
	  margin-right: 16px;
	  font-size :small!important;
	  line-height :1.25;
	}
	#GM_popup_tags{
	  width: 90%;
	  margin-left: 32px;
	  margin-right: 16px;
	  font-size :small!important;
	}

]]></>));

// ==UserScript==
// @name           Nico mylist API
// @namespace      http://efcl.info/
// @include        http://www.nicovideo.jp/mylist/*
// ==/UserScript==
(function () {
    var w = unsafeWindow;
    Mylist = {
        // マイリストの属性
        /*
         Mylist.groupListのツリー
         id (number): マイリストID
         user_id (number): マイリストのユーザーID
         name (string): マイリストのタイトル
         description (string): マイリスト説明文
         public (boolean): true // 公開状況
         default_sort (number): 1 (1-17)
         create_time (number): UNIX時間(util.unix2で戻せる)
         update_time (number): UNIX時間
         icon_id (number): 0
         sort_order (number): 0
         */
        // Mylist.groupList - my.CurrentGroupのコピー
        groupList: function () {
            return w.my.currentGroup;
        },
        /*
         my.currentItemsのツリー
         item_type (number): 0
         item_id (string): 接頭辞がない動画番号(常時)
         description (string): マイリスト登録者による説明文
         item_data
         video_id (string): 接頭辞がある動画番号(sm数字)
         title (string):  動画タイトル
         thumbnail_url (string): サムネイルURL
         first_retrieve (number): 投稿日時(UNIX時間)
         update_time (number): 更新日時(UNIX時間)
         view_counter (string): 再生数
         mylist_counter (string): マイリスト数
         num_res (string): コメント数
         group_type (string): default
         length_seconds (string): 再生時間(秒)
         deleted (string): 0 (削除状態0-3?)
         last_res_body (string): 最近のコメント(文字列)
         watch_id (string): 接頭辞なしの動画番号(コミュ、マイメモリー以外だと接頭辞がある)
         watch (number): 0
         create_time (number): マイリスト登録日時(UNIX時間)
         update_time (number): マイリスト更新日時(UNIX時間)
         */
        // Mylist.itemList - my.currentItemsのコピー
        itemList : function() {
            return w.my.currentItems;
        }
    }

    // utility関数群
    utils = {
        playlength : transPlaylength,
        unix2 : unixTodate,
        clone : clone
    }


    // 再生時間を分秒に変換
    function transPlaylength(length) {
        return (length / 60).toFixed(2).toString().split(".").join("分") + "秒";
    }

    // 10桁の数字(UNIXTIME)から2009/10/1 00:00形式で返す
    function unixTodate(x) {
        var t = new Date(x * 1000);
        return t.getFullYear() + "/" + fillZero(t.getMonth() + 1) + "/" + fillZero(t.getDate()) + " " + fillZero(t.getHours()) + ":" + fillZero(t.getMinutes()) + ":" + fillZero(t.getSeconds());
    }

    // http://d.hatena.ne.jp/javascripter/20080514/1210791575
    // 先頭を0で埋める デフォルト2桁
    function fillZero(num, digit) {
        var n = (digit) ? digit : 2;// デフォルト値
        var zero = new Array(n).join('0');//0をn-1文字分つなげた文字列を作る。n==4だと'000'
        var str = zero + num;//zeroとthisをくっつけた文字列を作る。
        var result = str.substr(-n);//strの後ろから、n文字分の文字列を取ってくる。
        return result;
    }

    // オブジェクトのコピーのコピーを作成
    function clone(obj) {
        return (typeof uneval == "function") ? eval(uneval(obj)) : false;
    }

})();

// $X(exp);
// $X(exp, context);
// $X(exp, type);
// $X(exp, context, type);
function $X(exp, context, type /* want type */) {
    if (typeof context == "function") {
        type = context;
        context = null;
    }
    if (!context) context = document;
    exp = (context.ownerDocument || context).createExpression(exp, function (prefix) {
        var o = document.createNSResolver(context)(prefix);
        if (o) return o;
        return (document.contentType == "application/xhtml+xml") ? "http://www.w3.org/1999/xhtml" : "";
    });

    switch (type) {
        case String:  return exp.evaluate(context, XPathResult.STRING_TYPE, null).stringValue;
        case Number:  return exp.evaluate(context, XPathResult.NUMBER_TYPE, null).numberValue;
        case Boolean: return exp.evaluate(context, XPathResult.BOOLEAN_TYPE, null).booleanValue;
        case Array:
            var result = exp.evaluate(context, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
            for (var ret = [], i = 0, len = result.snapshotLength; i < len; i++) {
                ret.push(result.snapshotItem(i));
            }
            return ret;
        case undefined:
            var result = exp.evaluate(context, XPathResult.ANY_TYPE, null);
            switch (result.resultType) {
                case XPathResult.STRING_TYPE : return result.stringValue;
                case XPathResult.NUMBER_TYPE : return result.numberValue;
                case XPathResult.BOOLEAN_TYPE: return result.booleanValue;
                case XPathResult.UNORDERED_NODE_ITERATOR_TYPE:
                    // not ensure the order.
                    var ret = [], i = null;
                    while ((i = result.iterateNext())) ret.push(i);
                    return ret;
            }
            return null;
            default: throw(TypeError("X: specified type is not valid type."));
    }
}

function getElementsByAttr(tag, attr, value) {
    var arrayEl = new Array();
    var el = document.getElementsByTagName(tag);
    for (i = 0,j = 0; i < el.length; i++) {
        if (el[i].getAttribute(attr) == value) {
            arrayEl[j] = el[i];
            j++;
        }
    }
    return arrayEl;
}
function getVideoInfos(g) {
    var aryInfo = [];
    for (var i = 0,l = (g.length < 3) ? g.length : 3; i < l; i++) {
        var tmp = g[i].item_data;
        aryInfo[i] = {
            title : tmp.title,
            url : "http://www.nicovideo.jp/watch/" + tmp.video_id,
            imgSrc :tmp.thumbnail_url,
            videoLength : "再生時間" + utils.playlength(tmp.length_seconds),
            retrieve : "投稿日 : " + utils.unix2(tmp.first_retrieve)
        }
    }
    return aryInfo;
}
function makeFromTemplate(obj) {
    var result = [];
    for (var i = 0,l = obj.length; i < l; i++) {
        var title = obj[i].title;
        var url = obj[i].url;
        var imgsrc = obj[i].imgSrc;
        var videoLength = obj[i].videoLength;
        var retrieve = obj[i].retrieve;
        var request = <div class="nicovideo_div">
            <a href={url} title={title} class="nicovideo_href">
                <img src={imgsrc} class="nicovideo_img" />
            </a>
            <div class="nicovideo_info">
                <p class="nicovideo_retrieve">{retrieve}</p>
                <p class="nicovideo_length">{videoLength}</p>
                <p class="nicovideo_link">
                    <a href={url} title={title} class="nicovideo_link">{title}</a>
                </p>
            </div>
            <br class="float_clear" />
        </div>
        result.push(request);
    }
    return result
}

var isAddEvent = false;
shortcut.add(window, GM_config.get("ShortCutKey"), function() {
    var tagName;
    try {
        tagName = $X('id("TagCloud")//a[contains(@href, "http://www.nicovideo.jp/tag/")]', document);
    } catch(e) {
    }
    //タグ名 : タグ数
    var inputTags = [];
    var defTag = "";
    if (tagName) {
        var tagObj = [];
        tagName.forEach(function(t, i) {
            var m = t.textContent.match(/(^.*?)\((\d+)\)$/);
            tagObj[i] = {name:m[1],sum:m[2]};
            if (!isAddEvent) {
                t.addEventListener("click", function(evt) {
                    evt.preventDefault();
                    updateTag(t);
                }, false);
            }
        });
        isAddEvent = true;
        // 降順に並び替え
        tagObj.sort(function(a, b) {
            log(a, b);
            return b["sum"] - a["sum"];
        })
        for (var i = 0,len = (tagObj.length > 3) ? 3 : tagObj.length; i < len; i++) {
            inputTags.push(tagObj[i].name);
        }
        // タグに色をつける
        tagsColoring(tagName, inputTags)
    }
    // DOM my.currentGroupにアクセス
    var group = Mylist.groupList();
    /* init */
    createPopup(group.name, '', inputTags.join(" "), function(title, str, tags) {
        if (str) {

            // DOM my.currentItemsにアクセス
            var items = Mylist.itemList();
            // templateでまとめる
            var videoData = makeFromTemplate(getVideoInfos(items));
            if (!videoData)
                return;
            var postData = '<div class="nicovideo_mylist"><p class="nicomylist_title"><a href="http://www.nicovideo.jp/mylist/' + group.id + '">' + group.name + '</a></p><p class="nicomylist_description">' + group.description + '</p>'
                    + videoData.join("\n")
                    + '</div>';
            var tagAry = tags.split(/\s/);
            /* init メタ情報を使って投稿先決める*/
            var t = new XMLRPC(metaBlog);
            title = (title) ? title : group.name;
            t.post(
                    GM_config.get("titlePre") + title, // タイトル
                    str.split("\n").join("<br />") + "<br />" + postData,
                    GM_config.get("category"),
                    tagAry,
                    function(res) {//callback
                        console.log(res);
                    }
                    );

        }
    }, true);
    var popup = new Draggable("GM_popup_container");

    function tagsColoring(ele, tags) {
        for (var i = 0,len = ele.length; i < len; i++) {
            ele[i].style.backgroundColor = null;
            for (var j = 0,l = tags.length; j < l; j++) {
                if (decodeURI(ele[i].href.split("/").pop()) == tags[j]) {
                    ele[i].style.backgroundColor = "#00dddd";
                    break;
                }
            }
        }
    }

    function updateTag(ele) {
        var Tags = document.getElementById("GM_popup_tags");
        var GMTags = Tags.value.split(" ");
        var word = decodeURI(ele.href.split("/").pop());
        if (ele.style.backgroundColor) {
            GMTags = GMTags.filter(function(x) {
                return x != word
            });
            ele.style.backgroundColor = null;
        } else {
            GMTags.push(word);
        }
        Tags.value = GMTags.join(" ");
        tagsColoring(tagName, GMTags)
    }
});
function log(m) {
    if (unsafeWindow.console) {
        unsafeWindow.console.log(m);
    } else {
        console.log(m); //GM_log(m)でも同じ。
    }
}