Created
January 30, 2009 12:11
-
-
Save azu/55041 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name favlist++ | |
// @namespace http://web.zgo.jp/ | |
// @include http://www.nicovideo.jp/mylist/* | |
// @include http://www.nicovideo.jp/user/* | |
// @include http://www.nicovideo.jp/myvideo/* | |
// @include http://www.nicovideo.jp/my* | |
// ==/UserScript== | |
(function () { | |
var w = (this.unsafeWindow || window), document = w.document; | |
var NicoNicoFavlist = { | |
version: "1.16", | |
getUserAgent: function () { | |
return "NicoNicoFavlist/" + NicoNicoFavlist.version + " Greasemonkey"; | |
} | |
}; | |
var Util = { | |
observe: function (elem, event, func, capture) { | |
capture = !!capture; | |
if (elem.attachEvent) { | |
elem.attachEvent("on" + event, func); | |
} else if (elem.addEventListener) { | |
elem.addEventListener(event, func, capture); | |
} else { | |
elem["on" + event] = func; | |
} | |
} | |
}; | |
var Config = { | |
checkInterval: 30 * 60, | |
maxNewVideos: 10, | |
hideCheckedList: false, | |
showInAllTabs: false, | |
show: function (elem) { | |
var ul = document.createElement("ul"); | |
ul.style.margin = "0px"; | |
ul.style.padding = "8px"; | |
ul.style.listStyleType = "none"; | |
this.addTextInput(ul, "更新チェック間隔", "favlistCheckInterval", Config.checkInterval, "10", "秒"); | |
this.addTextInput(ul, "新着動画数の上限", "favlistMaxNewVideos", Config.maxNewVideos, "10", "件まで"); | |
this.addCheckBox(ul, "新着がないマイリストを隠す", "favlistHideCheckedList", Config.hideCheckedList); | |
this.addCheckBox(ul, "カテゴリをまたいで表示", "favlistShowInAllTabs", Config.showInAllTabs); | |
elem.appendChild(ul); | |
}, | |
addTextInput: function (elem, label, name, value, size, unit) { | |
var li = document.createElement("li"); | |
li.className = "TXT12"; | |
li.style.fontWeight = "bold"; | |
li.style.marginBottom = "8px"; | |
li.innerHTML = '<label for="'+name+'">'+label+':</label><br>'; | |
var input = document.createElement("input"); | |
input.type = "text"; | |
input.id = name; | |
input.name = name; | |
input.value = value; | |
input.size = size; | |
li.appendChild(input); | |
if (unit) { | |
var span = document.createElement("span"); | |
span.innerHTML = unit; | |
span.style.marginLeft = "4px"; | |
li.appendChild(span); | |
} | |
elem.appendChild(li); | |
}, | |
addCheckBox: function (elem, label, name, value) { | |
var li = document.createElement("li"); | |
li.className = "TXT12"; | |
li.style.fontWeight = "bold"; | |
li.style.marginBottom = "4px"; | |
li.innerHTML = '<label for="'+name+'">'+label+'</label>'; | |
var check = document.createElement("input"); | |
check.type = "checkbox"; | |
check.id = name; | |
check.name = name; | |
check.value = "1"; | |
check.checked = !!value; | |
li.insertBefore(check, li.firstChild); | |
elem.appendChild(li); | |
}, | |
load: function () { | |
var checkInterval = GM_getValue("checkInterval"); | |
if (checkInterval !== undefined) Config.checkInterval = checkInterval; | |
var maxNewVideos = GM_getValue("maxNewVideos"); | |
if (maxNewVideos !== undefined) Config.maxNewVideos = maxNewVideos; | |
var hideCheckedList = GM_getValue("hideCheckedList"); | |
if (hideCheckedList !== undefined) Config.hideCheckedList = hideCheckedList; | |
var showInAllTabs = GM_getValue("showInAllTabs"); | |
if (showInAllTabs !== undefined) Config.showInAllTabs = showInAllTabs; | |
}, | |
save: function () { | |
var interval = document.getElementById("favlistCheckInterval").value; | |
try { | |
interval = w.parseInt(interval); | |
if (interval < 0) interval = 0; | |
Config.checkInterval = interval; | |
GM_setValue("checkInterval", interval); | |
} catch (e) { | |
w.alert("更新チェック間隔の値がおかしいです"); | |
return; | |
} | |
var maxnewvideos = document.getElementById("favlistMaxNewVideos").value; | |
try { | |
maxnewvideos = w.parseInt(maxnewvideos); | |
if (maxnewvideos < 0) maxnewvideos = 0; | |
Config.maxNewVideos = maxnewvideos; | |
GM_setValue("maxNewVideos", maxnewvideos); | |
} catch (e) { | |
w.alert("新着動画数の上限の値がおかしいです"); | |
return; | |
} | |
var hidechedkedlist = document.getElementById("favlistHideCheckedList").checked; | |
Config.hideCheckedList = hidechedkedlist; | |
GM_setValue("hideCheckedList", hidechedkedlist); | |
var showInAllTabs = document.getElementById("favlistShowInAllTabs").checked; | |
Config.showInAllTabs = showInAllTabs; | |
GM_setValue("showInAllTabs", showInAllTabs); | |
favlist.switchTab(0); | |
} | |
}; | |
var Video = function () { this.initialize.apply(this, arguments); }; | |
Video.prototype = { | |
initialize: function (mylist, id, title, uri, thumbnail, memo, timestamp) { | |
this.mylist = mylist; | |
this.id = id || false; | |
this.title = title || false; | |
this.uri = uri || false; | |
this.thumbnail = thumbnail || false; | |
this.memo = memo || false; | |
this.timestamp = timestamp || false; | |
this.container = false; | |
}, | |
serialize: function () { | |
return [ | |
this.id ? w.escape(this.id) : "", | |
this.title ? w.escape(this.title) : "", | |
this.uri ? w.escape(this.uri) : "", | |
this.thumbnail ? w.escape(this.thumbnail) : "", | |
this.memo ? w.escape(this.memo) : "", | |
this.timestamp ? w.escape(this.timestamp) : "" | |
].join("&"); | |
}, | |
unserialize: function (data) { | |
var r = []; | |
if (data) r = data.split(/&/); | |
this.id = r[0] ? w.unescape(r[0]) : false; | |
this.title = r[1] ? w.unescape(r[1]) : false; | |
this.uri = r[2] ? w.unescape(r[2]) : false; | |
this.thumbnail = r[3] ? w.unescape(r[3]) : false; | |
this.memo = r[4] ? w.unescape(r[4]) : false; | |
this.timestamp = r[5] ? w.unescape(r[5]) : false; | |
}, | |
updateByAtomEntry: function (entry) { | |
var m; | |
if (m = entry.match(/<title>(.*?)<\/title>/)) this.title = m[1]; | |
if (m = entry.match(/<link rel="alternate" type="text\/html" href="(.+?)"\/>/)) this.uri = m[1]; | |
if (this.uri && (m = this.uri.match(/watch\/(.+)/))) this.id = m[1]; | |
if (m = entry.match(/<img alt=".*?" src="(.+?)"/)) this.thumbnail = m[1]; | |
if (m = entry.match(/<p class="nico-memo">(.*?)<\/p>/)) this.memo = m[1]; | |
if (m = entry.match(/<published>(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}).*?<\/published>/)) { | |
this.timestamp = m[1]+"年"+m[2]+"月"+m[3]+"日 "+m[4]+":"+m[5]+":"+m[6]; | |
} | |
}, | |
getCaption: function () { | |
var caption = this.title || "(無題)"; | |
if (caption.length > 26) { | |
caption = caption.substr(0, 13) + "..." + caption.substr(-13); | |
} | |
return caption; | |
}, | |
show: function (elem) { | |
var li = document.createElement("li"); | |
li.style.clear = "both"; | |
li.style.padding = "4px 0px"; | |
li.style.borderTop = "1px dotted #CCC"; | |
var self = this; | |
var clearance = function () { self.mylist.clear(self); }; | |
var thumbLink = document.createElement("a"); | |
thumbLink.href = this.uri; | |
thumbLink.title = this.title; | |
try { thumbLink.style.cssFloat = "left"; } | |
catch (e) { thumbLink.style.styleFloat = "left"; } | |
thumbLink.style.marginRight = "4px"; | |
Util.observe(thumbLink, "click", clearance); | |
var thumb = document.createElement("img"); | |
thumb.className = "thumb_img"; | |
thumb.src = this.thumbnail; | |
thumb.width = "46"; | |
thumb.height = "34"; | |
thumbLink.appendChild(thumb); | |
li.appendChild(thumbLink); | |
if (this.timestamp) { | |
var time = document.createElement("p"); | |
var m = this.timestamp.split(/\D+/); | |
time.innerHTML = "<strong>" + | |
m[0].substr(-2) + "/" + m[1] + "/" + m[2] + " " + | |
m[3] + ":" + m[4] + ":" + m[5] + "</strong> 追加"; | |
time.className = "TXT10"; | |
li.appendChild(time); | |
} | |
var title = document.createElement("p"); | |
title.className = "TXT12"; | |
var titleLink = document.createElement("a"); | |
titleLink.href = this.uri; | |
titleLink.title = this.title; | |
titleLink.className = "video"; | |
titleLink.innerHTML = this.getCaption(); | |
Util.observe(titleLink, "click", clearance); | |
title.appendChild(titleLink); | |
li.appendChild(title); | |
var breaker = document.createElement("p"); | |
breaker.style.clear = "both"; | |
breaker.innerHTML = '<img src="img/_.gif" width="1" height="1">'; | |
li.appendChild(breaker); | |
if (this.memo) { | |
var memo = document.createElement("p"); | |
memo.innerHTML = this.memo; | |
memo.className = "TXT12"; | |
memo.style.backgroundColor = "#F7F7F7"; | |
memo.style.border = "1px solid #CCC"; | |
memo.style.padding = "4px"; | |
memo.style.marginTop = "4px"; | |
li.appendChild(memo); | |
} | |
elem.appendChild(li); | |
this.container = li; | |
}, | |
remove: function () { | |
if (this.container) { | |
this.container.parentNode.removeChild(this.container); | |
this.container = false; | |
} | |
} | |
}; | |
var Mylist = function () { this.initialize.apply(this, arguments); }; | |
Mylist.prototype = { | |
baseUri: "http://www.nicovideo.jp", | |
initialize: function (favlist, listId, title) { | |
this.favlist = favlist; | |
this.listId = listId || false; | |
this.title = title || false; | |
this.checked = { }; | |
this.newVideos = [ ]; | |
this.caption = false; | |
this.container = false; | |
this.videoList = false; | |
this.titleBar = false; | |
this.counter = false; | |
this.statusBar = false; | |
this.buttons = false; | |
this.toRemove = false; | |
}, | |
serialize: function () { | |
var checked = [ ]; | |
for (var k in this.checked) { checked.push(k); } | |
var newVideos = [ ]; | |
for (var i = 0, len = this.newVideos.length; i < len; i++) { | |
newVideos.push(this.newVideos[i].serialize()); | |
} | |
return [ | |
"0", /* for backward compatibility */ | |
this.listId ? w.escape(this.listId) : "", | |
this.title ? w.escape(this.title) : "", | |
checked.join(":"), | |
newVideos.join(":"), | |
this.caption ? w.escape(this.caption) : "" | |
].join(";"); | |
}, | |
unserialize: function (data) { | |
var r = []; | |
if (data) r = data.split(/;/); | |
// r[0] is userId, but not in use | |
this.listId = r[1] ? w.unescape(r[1]) : false; | |
if (/^\d+$/.test(this.listId)) this.listId = "mylist/" + this.listId; | |
this.title = r[2] ? w.unescape(r[2]) : false; | |
this.checked = { }; | |
if (r[3]) { | |
var checked = r[3].split(/:/); | |
for (var i = 0; i < checked.length; i++) { | |
if (checked[i]) { | |
this.checked[ checked[i] ] = true; | |
} | |
} | |
} | |
this.newVideos = [ ]; | |
if (r[4]) { | |
var vids = r[4].split(/:/); | |
for (var i = 0; i < vids.length; i++) { | |
if (vids[i]) { | |
var v = new Video(this); | |
v.unserialize(vids[i]); | |
this.newVideos.push(v); | |
} | |
} | |
} | |
this.caption = r[5] ? w.unescape(r[5]) : false; | |
}, | |
getUri: function () { | |
return this.baseUri + "/" + this.listId; | |
}, | |
getCaption: function () { | |
var caption = this.caption || this.title || "(無題)"; | |
if (caption.length > 26) { | |
caption = caption.substr(0, 13) + "..." + caption.substr(-13); | |
} | |
return caption; | |
}, | |
update: function () { | |
this.setStatus("更新中", "#333"); | |
this.newVideos = [ ]; | |
this.videoList.innerHTML = ""; | |
var self = this; | |
GM_xmlhttpRequest({ | |
method: "GET", | |
url: this.getUri() + "?rss=atom&nodescription=1&noinfo=1&sort=1", | |
headers: { "User-Agent": NicoNicoFavlist.getUserAgent() }, | |
onload: function (r) { | |
self.setStatus(false); | |
if (200 <= r.status && r.status < 300) { | |
self.updateByAtom(r.responseText); | |
} else if (r.status == 403) { | |
self.setStatus("非公開", "#C00", 3000); | |
} | |
}, | |
onerror: function (r) { | |
self.setStatus("更新失敗", "#C00", 3000); | |
}, | |
onreadystatechange: function (r) { | |
if (r.readyState == 4) { | |
self.favlist.updateCallback(this); | |
} | |
} | |
}); | |
}, | |
updateByAtom: function (xml) { | |
var m; | |
if (m = xml.match(/<title>(?:マイリスト )?(.+?)‐ニコニコ動画.*?<\/title>/)) { | |
this.title = m[1]; | |
} | |
var oldChecked = this.checked; | |
this.checked = { }; | |
var re_entry = /<entry>([\S\s]*?)<\/entry>/g; | |
while (m = re_entry.exec(xml)) { | |
var v = new Video(this); | |
v.updateByAtomEntry(m[1]); | |
if (v.id in oldChecked) { | |
this.checked[v.id] = true; | |
} else { | |
this.newVideos.push(v); | |
} | |
} | |
this.updateTitleBar(); | |
this.updateVideoList(); | |
this.favlist.save(); | |
}, | |
updateTitleBar: function () { | |
if (this.titleBar && this.titleBar.tagName.toUpperCase() == "A") { | |
this.titleBar.title = this.title; | |
this.titleBar.innerHTML = this.getCaption(); | |
if (this.newVideos.length > 0) { | |
this.titleBar.style.fontWeight = "bold"; | |
this.counter.innerHTML = "(" + this.newVideos.length + ")"; | |
this.counter.style.display = ""; | |
this.container.style.display = ""; | |
} else { | |
this.titleBar.style.fontWeight = ""; | |
this.counter.style.display = "none"; | |
if (Config.hideCheckedList && this.statusBar.style.display == "none") { | |
this.container.style.display = "none"; | |
} | |
} | |
} | |
}, | |
updateVideoList: function () { | |
if (!this.videoList) return; | |
this.videoList.innerHTML = ""; | |
var len = this.newVideos.length;//新着のサムネ数 | |
if (0 < Config.maxNewVideos && Config.maxNewVideos < len) { | |
len = Config.maxNewVideos; | |
} | |
for (var i = 0; i < len; i++) { | |
this.newVideos[i].show(this.videoList); | |
} | |
}, | |
show: function (elem, editting) { | |
var div = document.createElement("div"); | |
div.style.clear = "both"; | |
div.style.padding = "4px 0px"; | |
div.style.borderBottom = "1px solid #999"; | |
this.container = div; | |
var buttons = document.createElement("p"); | |
try { buttons.style.cssFloat = "right"; } | |
catch (e) { buttons.style.styleFloat = "right"; } | |
div.appendChild(buttons); | |
this.buttons = buttons; | |
var self = this; | |
this.toRemove = false; | |
this.addButton(buttons, "削除", function () { | |
self.toRemove = true; | |
self.container.parentNode.removeChild(self.container); | |
self.container = false; | |
}); | |
if (!editting) { | |
this.addButton(buttons, "クリア", function () { self.clearAll(); }); | |
} | |
var status = document.createElement("p"); | |
status.className = "TXT12"; | |
try { status.style.cssFloat = "right"; } | |
catch (e) { status.style.styleFloat = "right"; } | |
status.style.color = "#FFF"; | |
status.style.backgroundColor = "#666"; | |
status.style.fontWeight = "bold"; | |
status.style.padding = "0px 4px"; | |
status.style.lineHeight = "22px"; | |
status.style.display = "none"; | |
div.appendChild(status); | |
this.statusBar = status; | |
var h = document.createElement("p"); | |
h.className = "TXT12"; | |
h.style.padding = "2px 0px"; | |
div.appendChild(h); | |
if (editting) { | |
var input = document.createElement("input"); | |
input.type = "text"; | |
input.value = this.caption || this.title; | |
input.style.width = "170px"; | |
h.appendChild(input); | |
this.titleBar = input; | |
this.counter = null; | |
} else { | |
var a = document.createElement("a"); | |
a.href = this.getUri(); | |
a.title = this.title; | |
a.innerHTML = this.getCaption(); | |
h.appendChild(a); | |
this.titleBar = a; | |
var counter = document.createElement("span"); | |
counter.style.color = "#F33"; | |
counter.style.fontWeight = "bold"; | |
counter.style.marginLeft = "4px"; | |
counter.style.display = "none"; | |
h.appendChild(counter); | |
this.counter = counter; | |
} | |
var breaker = document.createElement("p"); | |
breaker.style.clear = "both"; | |
breaker.innerHTML = '<img src="img/_.gif" width="1" height="1">'; | |
div.appendChild(breaker); | |
if (editting) { | |
this.videoList = null; | |
} else { | |
var ul = document.createElement("ul"); | |
ul.style.clear = "both"; | |
ul.style.listStyleType = "none"; | |
ul.style.margin = "0px"; | |
ul.style.padding = "0px"; | |
div.appendChild(ul); | |
this.videoList = ul; | |
} | |
this.updateTitleBar(); | |
this.updateVideoList(); | |
elem.appendChild(div); | |
}, | |
showConfig: function (elem) { | |
this.show(elem, true); | |
}, | |
addButton: function (elem, caption, func) { | |
var btn = document.createElement("input"); | |
btn.type = "button"; | |
btn.value = caption; | |
btn.className = "submit"; | |
btn.style.marginLeft = "4px"; | |
Util.observe(btn, "click", func); | |
elem.appendChild(btn); | |
return btn; | |
}, | |
saveConfig: function () { | |
if (this.toRemove) { | |
this.remove(); | |
return; | |
} | |
if (!this.titleBar.value || this.titleBar.value == this.title) { | |
this.caption = false; | |
} else { | |
this.caption = this.titleBar.value; | |
} | |
if (this.caption != this.titleBar.value) { | |
this.caption = this.titleBar.value; | |
} | |
}, | |
remove: function () { | |
this.favlist.remove(this.listId); | |
if (this.container) { | |
this.container.parentNode.removeChild(this.container); | |
this.container = false; | |
} | |
}, | |
clear: function (video) { | |
if (!video) return; | |
for (var i = 0, len = this.newVideos.length; i < len; i++) { | |
if (this.newVideos[i] == video) { | |
this.newVideos.splice(i, 1); | |
} | |
} | |
video.remove(); | |
this.checked[video.id] = true; | |
this.updateTitleBar(); | |
this.favlist.save(); | |
}, | |
clearAll: function () { | |
for (var i = 0, len = this.newVideos.length; i < len; i++) { | |
var v = this.newVideos[i]; | |
v.remove(); | |
this.checked[v.id] = true; | |
} | |
this.newVideos = [ ]; | |
this.updateTitleBar(); | |
this.favlist.save(); | |
}, | |
setStatus: function (status, color, timeout) { | |
if (status) { | |
this.statusBar.innerHTML = status; | |
this.statusBar.style.backgroundColor = color; | |
this.statusBar.style.display = ""; | |
this.buttons.style.display = "none"; | |
this.container.style.display = ""; | |
if (timeout) { | |
var self = this; | |
w.setTimeout(function () { self.setStatus(false); }, timeout); | |
} | |
} else { | |
this.statusBar.style.display = "none"; | |
this.buttons.style.display = ""; | |
if (Config.hideCheckedList && this.newVideos.length == 0) { | |
this.container.style.display = "none"; | |
} | |
} | |
} | |
}; | |
var Favlist = function () { this.initialize.apply(this, arguments); }; | |
Favlist.prototype = { | |
initialize: function () { | |
this.id = arguments[0] || "favlist"; | |
this.list = { }; | |
this.tabs = [ ]; | |
this.container = false; | |
this.updateAllButton = false; | |
this.updateQueue = [ ]; | |
}, | |
save: function () { | |
GM_setValue(this.id, this.serialize()); | |
}, | |
load: function () { | |
this.unserialize(GM_getValue(this.id)); | |
}, | |
serialize: function () { | |
var data = []; | |
for (var k in this.list) { | |
data.push(this.list[k].serialize()); | |
} | |
return data.join("#"); | |
}, | |
unserialize: function (data) { | |
this.list = { }; | |
if (data) { | |
data = data.split(/#/); | |
for (var i = 0; i < data.length; i ++) { | |
var ml = new Mylist(this); | |
ml.unserialize(data[i]); | |
this.list[ml.listId] = ml; | |
} | |
} | |
}, | |
get: function (listId) { | |
return this.list[listId]; | |
}, | |
add: function (listId, title) { | |
var ml = new Mylist(this, listId, title); | |
this.list[listId] = ml; | |
this.save(); | |
}, | |
remove: function (listId) { | |
var ml = this.list[listId]; | |
if (ml) { | |
delete this.list[listId]; | |
this.save(); | |
} | |
}, | |
updateAll: function () { | |
var first = false; | |
for (var k in this.list) { | |
if (!first) { | |
first = this.list[k]; | |
} else { | |
this.updateQueue.push(this.list[k]); | |
this.list[k].setStatus("待機中", "#CCC"); | |
} | |
} | |
if (first) { | |
if (this.updateAllButton) { | |
this.updateAllButton.disabled = true; | |
} | |
first.update(); | |
} | |
}, | |
updateCallback: function (ml) { | |
if (this.updateQueue.length > 0) { | |
var ml = this.updateQueue.shift(); | |
ml.update(); | |
} else { | |
if (this.updateAllButton) { | |
this.updateAllButton.disabled = false; | |
} | |
} | |
}, | |
clearByVideoId: function (videoId) { | |
var toRemove; | |
if (videoId instanceof Array) { | |
var ids = { }; | |
for (var i = 0, len = videoId.length; i < len; i++) { | |
ids[videoId[i]] = true; | |
} | |
toRemove = function (id) { | |
return ids[id]; | |
} | |
} else { | |
toRemove = function (id) { | |
return (videoId == id); | |
} | |
} | |
var changed = false; | |
for (var k in this.list) { | |
var mylist = this.list[k], videos = mylist.newVideos; | |
var mylist_changed = false; | |
for (var i = videos.length - 1; i >= 0; i--) { | |
var video = videos[i]; | |
if (toRemove(video.id)) { | |
video.remove(); | |
mylist.checked[video.id] = true; | |
videos.splice(i, 1); | |
changed = true; | |
mylist_changed = true; | |
} | |
} | |
if (mylist_changed) mylist.updateTitleBar(); | |
} | |
if (changed) favlist.save(); | |
}, | |
addToPlaylist: function () { | |
if (typeof w.gm_playlistController == "undefined") return; | |
var addVideos = []; | |
for (var k in this.list) { | |
var mylist = this.list[k], videos = mylist.newVideos; | |
for (var i = 0, len = videos.length; i < len; i++) { | |
addVideos.push(videos[i]); | |
} | |
mylist.clearAll(); | |
} | |
if (addVideos.length > 0) { | |
w.gm_playlistController.pushVideos(addVideos); | |
} | |
}, | |
show: function (elem) { | |
var div = document.createElement("div"); | |
div.className = "mb16p4"; | |
div.style.position = "relative"; | |
var h = document.createElement("h2"); | |
div.appendChild(h); | |
var self = this; | |
this.tabs = []; | |
this.addTab(h, "一覧", function () { self.showList(); }); | |
this.addTab(h, "設定", function () { self.showConfig(); }); | |
var span = document.createElement("span"); | |
span.innerHTML = "favlist"; | |
span.style.display = "block"; | |
span.style.borderWidth = "2px"; | |
span.style.borderColor = "#FFF #FFF #333 #FFF"; | |
span.style.borderStyle = "solid"; | |
h.appendChild(span); | |
var container = document.createElement("div"); | |
container.style.clear = "both"; | |
container.style.position = "relative"; | |
container.style.paddingTop = "4px"; | |
div.appendChild(container); | |
this.container = container; | |
elem.insertBefore(div, elem.firstChild); | |
this.switchTab(0); | |
}, | |
addTab: function (elem, caption, func) { | |
var tab = document.createElement("a"); | |
tab.href = "javascript:void(0);"; | |
tab.innerHTML = caption; | |
tab.style.display = "block"; | |
tab.style.textAlign = "center"; | |
tab.style.textDecoration = "none"; | |
try { | |
tab.style.cssFloat = "right"; | |
} catch (e) { | |
tab.style.styleFloat = "right"; | |
} | |
tab.style.width = "3em"; | |
tab.style.color = "#333"; | |
tab.style.backgroundColor = "#FFF"; | |
tab.style.borderWidth = "2px"; | |
tab.style.borderColor = "#FFF #FFF #333 #FFF"; | |
tab.style.borderStyle = "solid"; | |
elem.insertBefore(tab, elem.firstChild); | |
this.tabs.push({ | |
tab: tab, | |
func: func | |
}); | |
var self = this; | |
Util.observe(tab, "click", function () { self.switchTab(tab); }); | |
return tab; | |
}, | |
switchTab: function (selectTab) { | |
if (this.updateQueue.length > 0) return; | |
if (typeof selectTab == "number") selectTab = this.tabs[selectTab].tab; | |
var func = false; | |
for (var i = 0, len = this.tabs.length; i < len; i++) { | |
var tab = this.tabs[i].tab; | |
if (tab == selectTab) { | |
tab.style.borderColor = "#333 #333 #FFF #333"; | |
func = this.tabs[i].func; | |
} else { | |
tab.style.borderColor = "#FFF #FFF #333 #FFF"; | |
} | |
} | |
if (func) func(); | |
}, | |
showList: function () { | |
this.container.innerHTML = ""; | |
for (var k in this.list) { | |
this.list[k].show(this.container); | |
} | |
var buttons = document.createElement("p"); | |
buttons.style.clear = "both"; | |
buttons.style.paddingTop = "4px"; | |
var self = this; | |
this.updateAllButton = this.addButton(buttons, "いますぐ更新", function () { self.updateAll(); }); | |
var checkPlaylist = function () { | |
if (typeof w.gm_playlistController != "undefined") { | |
var b = self.addButton(buttons, "プレイリストに移動", function () { self.addToPlaylist(); }); | |
b.style.marginLeft = "5px"; | |
return true; | |
} | |
} | |
var saveButton = document.createElement("input"); | |
saveButton.className = "submit"; | |
saveButton.type = "button"; | |
saveButton.value = "保存"; | |
saveButton.style.width = "5em"; | |
saveButton.style.fontWeight = "bold"; | |
var self = this; | |
Util.observe(saveButton, "click", function () { | |
for (var k in self.list) { | |
self.list[k].saveConfig(); | |
} | |
self.save(); | |
Config.save(); | |
}); | |
checkPlaylist() || setTimeout(checkPlaylist, 1); | |
this.container.appendChild(buttons); | |
this.container.appendChild(saveButton); | |
}, | |
addButton: function (elem, caption, func) { | |
var btn = document.createElement("input"); | |
btn.type = "button"; | |
btn.value = caption; | |
btn.className = "submit"; | |
Util.observe(btn, "click", func); | |
elem.appendChild(btn); | |
return btn; | |
}, | |
showConfig: function () { | |
this.container.innerHTML = ""; | |
for (var k in this.list) { | |
this.list[k].showConfig(this.container); | |
} | |
Config.show(this.container); | |
var p = document.createElement("p"); | |
p.style.borderTop = "1px solid #999"; | |
p.style.padding = "8px"; | |
var saveButton = document.createElement("input"); | |
saveButton.className = "submit"; | |
saveButton.type = "button"; | |
saveButton.value = "保存"; | |
saveButton.style.width = "5em"; | |
saveButton.style.fontWeight = "bold"; | |
var self = this; | |
Util.observe(saveButton, "click", function () { | |
for (var k in self.list) { | |
self.list[k].saveConfig(); | |
} | |
self.save(); | |
Config.save(); | |
}); | |
p.appendChild(saveButton); | |
this.container.appendChild(p); | |
}, | |
}; | |
var NicoHistory = { | |
videoIds: [ ], | |
loadFromCookie: function () { | |
NicoHistory.videoIds = [ ]; | |
if (w.document.cookie && /\bnicohistory\s*=\s*([^;]+)/.test(w.document.cookie)) { | |
var hist = RegExp.$1; | |
var m, re = /(?:^|%2C)(.+?)(?=%3A|$)/ig; | |
while (m = re.exec(hist)) { | |
this.videoIds.push(w.unescape(m[1])); | |
} | |
} | |
} | |
}; | |
var RegisterButton = function () { this.initialize.apply(this, arguments); }; | |
RegisterButton.prototype = { | |
initialize: function (favlist, listId, title) { | |
this.favlist = favlist; | |
this.listId = listId; | |
this.title = title; | |
this.button = false; | |
}, | |
show: function (elem) { | |
if (this.button) return; | |
var a = document.createElement("a"); | |
a.id = this.buttonId; | |
a.href = "javascript:void(0);"; | |
a.className = "TXT12"; | |
a.style.textDecoration = "none"; | |
a.style.padding = "2px 4px"; | |
a.style.margin = "3px 4px"; | |
a.style.border = "1px solid #CCC"; | |
a.style.backgroundColor = "#EEE"; | |
var self = this; | |
Util.observe(a, "click", function () { self.execute(); }); | |
elem.style.position = "relative"; | |
elem.appendChild(a); | |
this.button = a; | |
this.update(); | |
}, | |
update: function () { | |
if (!this.button) return; | |
if (this.favlist.get(this.listId)) { | |
this.button.innerHTML = '<span style="color:#F00;">×</span>'; | |
} else { | |
this.button.innerHTML = '<span style="color:#FC3;">★</span>'; | |
} | |
}, | |
execute: function () { | |
if (this.favlist.get(this.listId)) { | |
this.favlist.remove(this.listId); | |
} else { | |
this.favlist.add(this.listId, this.title); | |
GM_setValue("lastUpdate", 0); | |
} | |
this.update(); | |
} | |
}; | |
Config.load(); | |
var favlist = new Favlist(); | |
favlist.load(); | |
var m; | |
if (m = w.location.href.match(/nicovideo\.jp\/mylist\/(?:\d+\/)?(\d+)(?!.*rss=)/)) { | |
var h1 = document.getElementsByTagName("h1"); | |
if (h1 && h1.length > 0) { | |
var button = new RegisterButton(favlist, "mylist/" + m[1], h1[0].innerHTML); | |
button.show(h1[0]); | |
} | |
} else if (m = w.location.href.match(/nicovideo\.jp\/(?:myvideo|user)\/(\d+)(?!.*rss=)/)) { | |
var h1 = document.getElementsByTagName("h1"); | |
if (h1 && h1.length > 0) { | |
var title = document.title.match(/^(.+)さんの/) ? RegExp.$1 + "さんの投稿動画" : "投稿動画(" + m[1] + ")"; | |
var button = new RegisterButton(favlist, "myvideo/" + m[1], title); | |
button.show(h1[0]); | |
} | |
} else if (m = w.location.href.match(/nicovideo\.jp\/my?/)){ | |
NicoHistory.loadFromCookie(); | |
if (NicoHistory.videoIds.length > 0) { | |
favlist.clearByVideoId(NicoHistory.videoIds); | |
} | |
var showFavlist = function () { | |
var parentContainer; | |
var xp = "//div[@class='content_312']"; | |
var r = document.evaluate(xp, document, null, | |
XPathResult.FIRST_ORDERED_NODE_TYPE, null); | |
if (r) parentContainer = r.singleNodeValue; | |
if (parentContainer) { | |
favlist.show(parentContainer); | |
return true; | |
} else { | |
return false; | |
} | |
} | |
if (showFavlist()) { | |
if (w.Category) { | |
var oldCategoryUpdate = w.Category.update; | |
if (oldCategoryUpdate) { | |
w.Category.update = function () { | |
oldCategoryUpdate.apply(w.Category, arguments); | |
if (Config.showInAllTabs) { | |
showFavlist(); | |
} else { | |
w.Category.update = oldCategoryUpdate; | |
} | |
} | |
} | |
} | |
if (Config.checkInterval > 0) { | |
var now = w.Math.floor((new Date()).getTime() / 1000); | |
var last = GM_getValue("lastUpdate") || 0; | |
if (last + Config.checkInterval < now) { | |
GM_setValue("lastUpdate", now); | |
favlist.updateAll(); | |
} | |
} | |
} | |
} | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment