There are 12 previous versions of this script.
// ==UserScript==
// @name TumblrTagCommand
// @namespace http://whym.github.com
// @description Minibuffer command for tagging Tumblr posts. Type 'p' to mark/unmark a post and type 'g' to tag. Requires Minibuffer, LDRize & Autopagerize.
// @include http://www.tumblr.com/dashboard*
// @include http://www.tumblr.com/show/*
// @include http://www.tumblr.com/drafts*
// @include http://www.tumblr.com/queue*
// @include http://www.tumblr.com/tumblelog/*
// @include http://*.tumblr.com/tagged/*
// @include http://*.tumblr.com/post/*
// @include http://*.tumblr.com/private/*
// @include http://*.tumblr.com/search/*
// @include http://*.tumblr.com/page/*
// @include http://*.tumblr.com/archive/*
// @include http://*.tumblr.com/
// @version 0.0.6
// ==/UserScript==
// most parts are copied from ReblogCommand
// http://coderepos.org/share/browser/lang/javascript/userscripts/reblogcommand.user.js
(function() {
const KEY_TAG = 'g';
const KEY_TAG_ALL = 'G';
const COMMAND_TAG = 'tumblr-tag-add';
const COMMAND_POSTS = 'tumblr-posts';
const ALLOW_OWN_DOMAIN = true;
const REGEXP_SEPARATOR = /,/;
const SEPARATOR = ',';
var boot = function() {
var $X = window.Minibuffer.$X;
var D = window.Minibuffer.D;
var createDocumentFromString = window.Minibuffer.createDocumentFromString;
// ----------------------------------------------------------------------------
// Tumblr Tag
// ----------------------------------------------------------------------------
function parseTagList(args) {
var ret = [];
if ( !(args instanceof Array) ) {
args = [args];
}
args.forEach(function(x){
x = (''+x).trim();
if (x.length > 0) {
ret = ret.concat(x.split(REGEXP_SEPARATOR).map(function(x){return x.trim();}));
}
});
return ret;
}
Array.prototype.uniq = function() {
var ret = [];
var result = this.reduce(function(res, item) {
if (!res.found[item]) {
res.values.push(item);
res.found[item] = 1;
ret.push(item);
};
return res;
}, { values: [], found: {}});
return ret;
};
Array.prototype.remove = function(x) {
var removed = {};
if ( x instanceof Array ) {
x.forEach(function(x){
removed[x] = 1;
});
} else {
removed[x] = 1;
}
return this.filter(function(item) {
return !removed[item];
});
};
if ( String.prototype.trim == undefined ) {
String.prototype.trim = function() {
return this.replace(/^\s+|\s+$/, '');
};
}
function isTumblrDashboardURL(url) {
return url.match("^http://www\\.tumblr\\.com/dashboard") ? true : false;
}
function isTumblrUserURL(url) {
return url.match("^https?://[^.]+\\.tumblr\\.com/(post|private)/(\\d+)") ||
// tumblr allow to use own domain. but this is risky.
// $X('id("tumblr_controls")[self::iframe]', Boolean)
(ALLOW_OWN_DOMAIN && url.match("^https?://[^/]+/(post|private)/(\\d+)")) ? true : false;
}
function getIDByPermalink(url) {
if (isTumblrUserURL(url)) {
return RegExp.$2;
}
// return what ?
return false;
}
function getURLByID(id, token) {
return "http://www.tumblr.com/edit/" + id + "?redirect_to=/dashboard";
}
// copy from tombloo
function unescapeHTML(s) {
return s.replace(/"/g, '"')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/&/g, '&');
}
// copy from tombloo
function getReblogToken(url) {
url = unescapeHTML(url);
if (/&pid=([^&]*)&rk=([^&\"]*)/.test(url) || /\/reblog\/([^\/]+)\/([^?]*)/.test(url))
return {
id : RegExp.$1,
token : RegExp.$2
};
}
function parseParams(doc) {
// name() returns in lower case on fx3.6
var elms = $X('id("edit_post")//*[translate(name(),"input", "INPUT") ="INPUT" or translate(name(),"textarea", "TEXTAREA")="TEXTAREA" or translate(name(),"select", "SELECT")="SELECT"]', doc);
var params = {};
elms.forEach(function(elm) {
params[elm.name] = elm.value;
});
return params;
}
function createPostData(params) {
var arr = [];
for (var param in params) {
if (param != "preview_post" && param != "send_to_twitter") {
arr.push(encodeURIComponent(param));
arr.push("=");
arr.push(encodeURIComponent(params[param]));
arr.push("&");
}
}
return arr.join('');
}
function edittags(aURL, appends, removes) {
var id = getIDByPermalink(aURL);
var d;
with (D()) {
d = Deferred();
if (!id) {
wait(0).next(function() { d.call(); });
return d;
}
}
var message = '';
if (appends.length > 0) {
message += 'Adding '+appends.join(SEPARATOR);
}
if (removes.length > 0) {
message += (message.length > 0 ? ', removing ': 'Removing ')+removes.join(SEPARATOR);
}
window.Minibuffer.status(COMMAND_TAG+id, message+' ...');
d = D();
var url = aURL;
var editd = d.xhttp.get(url).
next(function(res) {
var token = getReblogToken(res.responseText.match('iframe src="((?:\\"|[^"])*)"')[1]);
url = getURLByID(token.id, token.token);
return d.xhttp.get(url);
}).
next(function(res) {
var params = parseParams(createDocumentFromString(res.responseText));
params['post[tags]'] = parseTagList(params['post[tags]']).concat(appends).remove(removes).uniq().join(SEPARATOR);
//if(!confirm(params['post[tags]'])){return d;}
if (!params.form_key)
editd.fail("invalid params");
return d.xhttp.post(url, createPostData( params ));
}).
next(function(res) {
if (res.status == 200) {
if ( ! res.finalUrl.match( /^http:\/\/www\.tumblr\.com\/dashboard/ ) )
editd.fail("unexpected response: " + res.finalUrl);
else
window.Minibuffer.status(COMMAND_TAG+id, message+' ... done.', 100);
} else {
window.Minibuffer.status(COMMAND_TAG+id, message+' ... error '+res.status+' .', 100);
editd.fail(res.status + 'in adding tag');
}
d.call();
}).
error(function(res) {
window.Minibuffer.status(COMMAND_TAG+id, message+' ... error.', 100);
if (confirm('error: '+res+', edit manually ? \n' + url))
editTagManually(url);
d.call();
});
return d;
}
function editTagManually(aURL) {
var url = aURL;
if (url.match(/\/edit\//)) {
GM_openInTab(url);
return;
}
var d = D();
d.xhttp.get(url).
next(function(res) {
var token = getReblogToken(res.responseText.match('iframe src="((?:\\"|[^"])*)"')[1]);
url = getURLByID(token.id, token.token);
GM_openInTab(url);
});
}
// ----------------------------------------------------------------------------
// Command
// ----------------------------------------------------------------------------
function getTargetCommand() {
var target_cmd = '';
if (isTumblrUserURL(window.location.href)) {
target_cmd = 'location';
} else if (window.LDRize) {
target_cmd = 'pinned-or-current-link';
} else {
target_cmd = 'location';
}
return target_cmd;
}
window.Minibuffer.addShortcutkey({
key: KEY_TAG,
description: 'Tag Tumblr posts',
command: function() {
var target_cmd = getTargetCommand();
var clear_pin = (target_cmd == 'pinned-or-current-link') ? ' | clear-pin' : '';
var tags = prompt("Input new tags and the tags to be deleted.\n(ex. To add 'picture' and remove 'pict', use 'picture,-pict'.)");
window.Minibuffer.execute(target_cmd + ' | '+[COMMAND_TAG, tags].join(' ')+clear_pin);
}
});
window.Minibuffer.addShortcutkey({
key: KEY_TAG_ALL,
description: 'Tag all Tumblr posts in screen',
command: function() {
var target_cmd = 'tumblr-posts';
var tags = prompt("Input new tags and the tags to be deleted.\n(ex. To add 'picture' and remove 'pict', use 'picture,-pict'.)");
window.Minibuffer.execute(target_cmd + ' | '+[COMMAND_TAG, tags].join(' '));
}
});
window.Minibuffer.addCommand({
name: COMMAND_POSTS,
command: function(stdin) {
var linkx = window.LDRize.getSiteinfo().link;
var parax = window.LDRize.getSiteinfo().paragraph;
var getfirst = function(x){
return x[0] != undefined ? x[0] : x;
};
var items = $X(parax).map(function(i){ return getfirst($X(linkx, i));});
return items;
}
});
window.Minibuffer.addCommand({
name: COMMAND_TAG,
command: function(stdin) {
var args = parseTagList(this.args.join(' '));
var urls = [];
if (!stdin.length) {
if (isTumblrDashboardURL(window.location.href.toString())) {
var link = window.Minibuffer.execute('current-link');
if (link) urls = [link.toString()];
} else {
// command line is just 'tumblr-tag-add'
urls = [window.location.href];
}
} else {
urls = [];
stdin.forEach(function(a){
if (a && typeof a == 'string') {
// command line is 'location | tumblr-tag-add'
urls.push(a);
} else if (a && a.nodeName && a.href && a.nodeName == 'A') {
// command line is 'pinned-or-current-link | tumblr-tag-add'
urls.push(a.href);
} else {
window.Minibuffer.status(COMMAND_TAG, 'Unsupported input: ' + a, 1000);
}
});
}
if (urls.length == 0){
window.Minibuffer.status(COMMAND_TAG, 'no input ', 1000);
return null;
}
// edit tags
if (args.length >= 1) {
var removes = [];
var appends = [];
args.forEach(function(x){
if (x.charAt(0) == '-') {
removes.push(x.substr(1));
} else {
if (x.charAt(0) == '+')
x = x.substr(1);
appends.push(x);
}
});
appends = parseTagList(appends).uniq();
removes = parseTagList(removes).uniq();
urls = urls.filter(isTumblrUserURL);
if (!urls.length) return stdin;
var lst = urls.map(function(x){return edittags(x, appends, removes);});
if (lst.length > 1) {
with (D()) {
parallel(lst).wait(2).
next(function() { window.Minibuffer.status(COMMAND_TAG, 'Everything is OK', 1000); });
}
}
return stdin;
} else {
window.Minibuffer.status(COMMAND_TAG, 'No tag is specified', 1000);
return null;
}
}
});
};
if (document.body.id == 'tinymce')
return;
if (window.Minibuffer) {
boot();
} else {
window.addEventListener('GM_MinibufferLoaded', boot, false);
}
})();