Skip to content

Instantly share code, notes, and snippets.

@saitamanodoruji
Last active April 26, 2024 10:18
Show Gist options
  • Save saitamanodoruji/5690960 to your computer and use it in GitHub Desktop.
Save saitamanodoruji/5690960 to your computer and use it in GitHub Desktop.
Tumblr Bookmarker
// ==UserScript==
// @name Tumblr Bookmarker
// @description Bookmark posts on your dash to return to later
// @namespace http://userscripts.org/users/113977
// @include http://www.tumblr.com/blog/*
// @include http://www.tumblr.com/drafts*
// @include http://www.tumblr.com/queue*
// @include http://www.tumblr.com/likes*
// @include http://www.tumblr.com/messages*
// @include http://www.tumblr.com/dashboard*
// @include http://www.tumblr.com/tagged*
// @version 0.2.10.4
// @date 2013-09-07
// @creator Jeremy Cutler
// @contributer saitamanodoruji
// @require http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js
// ==/UserScript==
(function() {
var bmi = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAANCAYAAAB2HjRBAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAABl0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuNtCDrVoAAABASURBVDhPY2CgNvj///9mdEy0HaOaIYFH9wDLhIU8qTZnyho4gpwMNoAUzWCNQGwEM4BozTCNIA0wA4jWTKxCAEx4sLT85fObAAAAAElFTkSuQmCC';
GM_addStyle('#right_column .dashboard_nav_item ul.dashboard_subpages li a .icon.dashboard_controls_bookmark { background-image:url("' + bmi + '") !important; }');
jQuery.noConflict();
var mimg = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAAOCAYAAAAi2ky3AAAABGdBTUEAALGPC/xhBQAAABl0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuNtCDrVoAAAC0SURBVDhP7ZIxCsJAFETXPUWEVFZ7CyE30lIQ77EQfmy021oPYWPlCbzBdgtxZvkhKX5nmw8PhoGZ4jOb4f4cnXHvz9ey3Wt3Mn3HIovjRUaL/XU7WqxF87/WH82b+mdHBcMkdaCLogJNqrd4doEm1ZsGmRFOCvVUlBFOCvVUlBFOCnUtysPtISAoQg+hfDj3AoIi9BDK3dAICIrQcwhH0AKvUEeESQu8Qh0RJm3XN75CDe8HWZs6UiUIC2gAAAAASUVORK5CYII=';
function LS_getValue(key,defVal) {
var retval = window.localStorage.getItem(key);
if (retval == undefined || retval == null || retval == "") {
return defVal;
}
else
return retval;
}
function LS_setValue(key,val) {
window.localStorage.setItem(key,val);
}
function serializeMarks(a) {
var s = "";
a.sort().reverse();
for (i=0; i<a.length; i++) {
s = a[i][0] + ";" + a[i][1] + (a[i][2] ? ";" + a[i][2] : "")
+ (i>0 ? "," : "") + s;
}
return s;
}
function parseMarks(s) {
var arr = new Array();
var ms = s.split(",");
for (i=0; i<ms.length; i++) {
var cm = ms[i].split(";");
if (cm.length == 2) {
arr.push([cm[0],cm[1]]);
} else if (cm.length == 3) {
arr.push([cm[0],cm[1],cm[2]]);
}
}
arr.sort().reverse();
return arr;
}
function markOver() {
var bp = jQuery(this).css("background-position");
if (bp == "" || bp.charAt(0) == "0")
jQuery(this).css("background-position","-6px 0px");
}
function markOut() {
var bp = jQuery(this).css("background-position");
if (bp == "" || bp.charAt(1) == "6")
jQuery(this).css("background-position","0px 0px");
}
function markClick(e) {
if (e.which == 1) {
if (jQuery(this).hasClass("s113977_ismarked")) {
removeMark(this.id.match(/[0-9]*$/)[0]);
}
else {
addMark(this.id.match(/[0-9]*$/)[0], this.getAttribute('data-dsbd-timestamp'));
}
return false;
}
}
function addMark(postID, dsbd_timestamp) {
var timestamp = new Date().toLocaleFormat('%Y-%m-%d %H:%M:%S');
var marks = parseMarks(LS_getValue("tbr_Bookmarks",""));
marks.push([timestamp,postID,dsbd_timestamp]);
LS_setValue("tbr_Bookmarks",serializeMarks(marks));
generateList();
}
function removeMark(post) {
var marks = parseMarks(LS_getValue("tbr_Bookmarks",""));
for (i=0; i<marks.length; i++) {
if (marks[i][1] == post) {
break;
}
}
marks.splice(i,1);
LS_setValue("tbr_Bookmarks",serializeMarks(marks));
generateList();
}
function doMarks() {
var posts = jQuery('div[id^="post_"]:not(.bookmarkAdded):not(.post_tab_switching)');
posts.addClass('bookmarkAdded');
posts.each(function(i){
var post_controls_inner = jQuery(this).find('div.post_controls_inner');
var post_id = jQuery(this).attr('id').match(/[0-9]*$/)[0];
var dsbd_date_str = jQuery(this).find('.post_permalink').attr('title').toString();
var dsbd_unixtime = getUnixTimeFromDsbdDateString(dsbd_date_str, post_id);
var dsbd_timestamp = new Date(dsbd_unixtime).toLocaleFormat('%Y-%m-%d %H:%M:%S');
var node = jQuery('<a class="s113977_mark" id="bookmark_' + post_id + '" title="Bookmark" href="#" style="border-width:0;height:14px;width:6px;vertical-align:16px;display:inline-block;background-image:url(' + mimg + ');background-repeat:no-repeat;background-attachment:scroll;background-position:0 0;margin:0 5px 0 16px" onclick="return false;" data-dsbd-timestamp="' + dsbd_timestamp + '"></a>');
node.appendTo(post_controls_inner).click(markClick).mouseover(markOver).mouseout(markOut);
});
}
function getMarkText(timestamp, post_id, dsbd_timestamp) {
var mark_text = [
'<li id="mark_' + post_id + '">',
'<a href="/dashboard/2/' + (Number(post_id) + 1) + '" target="_blank">',
'<span class="icon dashboard_controls_bookmark"></span>',
'<span class="mark_date">' + timestamp + '</span>',
dsbd_timestamp ? '<br />' : '',
'<span class="mark_dsbd_date">' + (dsbd_timestamp ? '&nbsp;&nbsp;&nbsp;&nbsp;└' + dsbd_timestamp : '') + '</span>',
'</a>',
'<a id="unmark_' + post_id + '" class="s113977_unmarker tracked_tag_control" onclick="return false;" href="#">x</a>',
'</li>'
].join('');
return mark_text;
}
function marklistClick(e) {
if (/s113977_unmarker/.test(e.target.className) && e.which == 1) {
removeMark(e.target.id.match(/[0-9]*$/)[0]);
return false;
}
}
function generateList() {
var marks = parseMarks(LS_getValue("tbr_Bookmarks",""));
var marklist = jQuery('#s113977_marklist');
if (marks.length == 0) {
jQuery('#posts a.s113977_ismarked').css("background-position","0px 0px").removeClass("s113977_ismarked");
marklist.empty().parent().hide();
return true;
}
marklist.parent().show();
var markitems = marklist.find('li');
if (markitems.length > 0) {
var idx = 0;
markitems.each(function(i) {
var cd = jQuery(this).find('span.mark_date').html();
if (idx > marks.length-1 ||
cd > marks[idx][0]) {
jQuery("#bookmark_" + this.id.match(/[0-9]*$/)[0]).css("background-position","0px 0px").removeClass("s113977_ismarked");
jQuery(this).remove();
}
else if (cd < marks[idx][0]) {
while (idx < marks.length && cd <= marks[idx][0]) {
jQuery("#bookmark_" + marks[idx][1]).css("background-position","-12px 0px").addClass("s113977_ismarked");
if (cd != marks[idx][0]) {
jQuery(this).before(getMarkText(marks[idx][0],marks[idx][1],marks[idx][2] ? marks[idx][2] : undefined));
}
idx++;
}
}
else {
jQuery("#bookmark_" + marks[idx][1]).css("background-position","-12px 0px").addClass("s113977_ismarked");
idx++;
}
});
for(; idx<marks.length; idx++) {
jQuery("#bookmark_" + marks[idx][1]).css("background-position","-12px 0px").addClass("s113977_ismarked");
marklist.append(getMarkText(marks[idx][0],marks[idx][1],marks[idx][2] ? marks[idx][2] : undefined));
}
}
else {
for (i=0; i<marks.length; i++) {
jQuery("#bookmark_" + marks[i][1]).css("background-position","-12px 0px").addClass("s113977_ismarked");
marklist.append(getMarkText(marks[i][0],marks[i][1],marks[i][2] ? marks[i][2] : undefined));
}
}
}
if (document.body.id != "tinymce" &&
document.body.id != "dashboard_edit_post") {
if (/drafts$/.test(location) == false &&
/queue$/.test(location) == false &&
/messages$/.test(location) == false)
doMarks();
var list = jQuery('<div class="dashboard_nav_item" style="padding-left:0;position:relative;"><div class="dashboard_nav_title">Bookmarks</div><ul id="s113977_marklist" class="dashboard_subpages"></ul></div>');
var pos = jQuery("#dashboard_controls_radar_buttons");
if (pos.length > 0) {
pos.parent().before(list);
}
else {
jQuery("#right_column").append(list);
}
list.click(marklistClick);
generateList();
}
function refreshMarks() {
var marks = parseMarks(LS_getValue("tbr_Bookmarks",""));
jQuery("#posts a.s113977_ismarked").each(function(){
var remove = true;
for (i=0; i<marks.length; i++) {
if (this.id == "bookmark_" + marks[i][1]) {
remove = false;
break;
}
}
if (remove) jQuery(this).css("background-position","0px 0px").removeClass("s113977_ismarked");
});
for (i=0; i<marks.length; i++) {
jQuery("#bookmark_" + marks[i][1]).css("background-position","-12px 0px").addClass("s113977_ismarked");
}
generateList();
}
function tbr_113977() {
if (/drafts$/.test(location) == false &&
/queue$/.test(location) == false &&
/messages$/.test(location) == false)
doMarks();
refreshMarks();
}
if (document.body.id != "tinymce" &&
document.body.id != "dashboard_edit_post") {
tbr_113977();
document.addEventListener('DOMNodeInserted', tbr_113977, false);
window.addEventListener('storage', tbr_113977, false);
}
// ======== Utilities for Date Correction ========
// a.post_permalink の title に入っている日付文字列と Post ID を元に
// ポストが作られた Unix time を求める
function getUnixTimeFromDsbdDateString(dsbdDateStr, dsbdPostNo) {
var utime;
var dateArr = dsbdDateStr.replace(/(?:View post|投稿を確認する) - /, '').split(' ');
var type = dateArr.length;
var curDate = new Date();
if (type == 1) {
// View post - 5:17am
var formattedTime = getFormattedTime(dsbdDateStr.replace('View post - ', ''));
var timestamp = curDate.toString().replace(/\d\d:\d\d:\d\d/, formattedTime);
utime = new Date(timestamp).getTime();
} else if (type == 2) {
// View post - Thursday, 11:53pm
var diffInWeek;
var day = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
day.forEach(function(e, i) {
if( e == dateArr[0].replace(',', '') ) {
diffInWeek = curDate.getDay() - i > 0 ?
curDate.getDay() - i :
curDate.getDay() - i + 7;
}
});
var formattedTime = getFormattedTime(dsbdDateStr.replace(/^[^,]+, /, ''));
var timestamp = curDate.toString().replace(/\d\d:\d\d:\d\d/, formattedTime);
utime = new Date(timestamp).getTime() - diffInWeek * 86400000;
} else if (type == 3) {
// View post - June 8th, 8:46pm
var formattedDateStr = [
curDate.getFullYear(),
dateArr[0],
dateArr[1].replace(/(?:st|nd|rd|th)/, ''),
getFormattedTime(dateArr[2])
].join(' ');
utime = new Date(formattedDateStr).getTime();
} else if (type == 4) {
// View post - March 29th 2007, 8:38pm
var formattedDateStr = [
dateArr[0],
dateArr[1].replace(/(?:st|nd|rd|th)/, ''),
dateArr[2],
getFormattedTime(dateArr[3])
].join(' ');
utime = new Date(formattedDateStr).getTime();
}
return correctDsbdUTime(utime, type, dsbdPostNo);
}
// いくつかの日付で日付文字列が間違っているので修正する
function correctDsbdUTime(utime, type, dsbdPostNo) {
var cUTime; //corrected Unix time
var timestamp = new Date(utime).toLocaleFormat('%Y-%m-%dT%H:%M:%S+09:00');
if (1230649200000 <= utime && utime < 1230735600000
&& dsbdPostNo < 31818629) {
// 2007-12-31 is displayed as 2008 by mistake
cUTime = new Date(timestamp.replace(/^2008/, '2007')).getTime();
} else if (1262012400000 <= utime && utime < 1262271600000
&& dsbdPostNo < 175958681) {
// 2008-12-29, 2008-12-30, 2008-12-31 are displayed as 2009 by mistake
cUTime = new Date(timestamp.replace(/^2009/, '2008')).getTime();
} else if (1230735600000 <= utime && utime < 1230994800000
&& dsbdPostNo > 175958681) {
// 2010-01-01, 2010-01-02, 2010-01-03 are displayed as 2009 by mistake
cUTime = new Date(timestamp.replace(/^2009/, '2010')).getTime();
} else if (1262271600000 <= utime && utime < 1262444400000
&& dsbdPostNo > 973060715) {
// 2011-01-01, 2011-01-02 are displayed as 2010 by mistake
cUTime = new Date(timestamp.replace(/^2010/, '2011')).getTime();
} else if (1293807600000 <= utime && utime < 1293894000000
&& dsbdPostNo > 5381076679) {
// 2012-01-01 is displayed as 2011 by mistake
cUTime = new Date(timestamp.replace(/^2011/, '2012')).getTime();
}
// same day of previous years displayed as current year
if (type == 1) {
var currentYear = new Date().getFullYear();
if (dsbdPostNo < 22717143) {
// to 2007
cUTime = rewindYear(utime, currentYear - 2007);
} else if (dsbdPostNo < 67667869) {
// to 2008
cUTime = rewindYear(utime, currentYear - 2008);
} else if (dsbdPostNo < 309781747) {
// to 2009
cUTime = rewindYear(utime, currentYear - 2009);
} else if (dsbdPostNo < 2542286951) {
// to 2010
cUTime = rewindYear(utime, currentYear - 2010);
} else if (dsbdPostNo < 15082228675) {
// to 2011
cUTime = rewindYear(utime, currentYear - 2011);
} else if (dsbdPostNo < 39306789337) {
// to 2012
cUTime = rewindYear(utime, currentYear - 2012);
}
}
// for 2012-12-31
if (type == 2 && 39217020996 < dsbdPostNo && dsbdPostNo < 39306789337) {
cUTime = new Date(timestamp.replace(/\d{4}-\d{2}-\d{2}/, '2012-12-31')).getTime();
}
return cUTime || utime;
}
// n 年前の同日の Unix time を求める
function rewindYear(utime, n) {
var utimeDateStr = new Date(utime).toISOString();
var utimeYear = Number(utimeDateStr.match(/^\d{4}/)[0]);
var rewindedYear = utimeYear - n;
var rewindedDateStr = utimeDateStr.replace(/^\d{4}/, rewindedYear);
var rewindedUTime = new Date(rewindedDateStr).getTime();
return rewindedUTime;
}
// 時刻文字列を 24 h 形式にする
// ex. 1) '9:17am' -> '09:17'
// ex. 2) '5:36pm' -> '17:36'
function getFormattedTime(timeStr) {
var timeArr = timeStr.split(':');
timeArr[0] = Number(timeArr[0]);
if (/pm/.test(timeArr[1])) {
timeArr[0] = (timeArr[0] + 12).toString();
} else if (timeArr[0].toString().length == 1) {
timeArr[0] = '0' + timeArr[0];
} else {
timeArr[0] = timeArr[0].toString().replace('12', '00');
}
timeArr[1] = timeArr[1].replace(/(?:am|pm)/, '');
return timeArr.join(':');
}
function update(t, s){
for(var p in s)
t[p] = s[p]
return t
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment