Last active
December 13, 2015 17:48
-
-
Save saitamanodoruji/4950258 to your computer and use it in GitHub Desktop.
TumblrTagCommand
This file contains hidden or 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 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/blog/* | |
// @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/ | |
// @run-at document-end | |
// @grant GM_openInTab | |
// @version 0.0.10.0 | |
// @update 2013-06-11 | |
// @updateURL https://gist.github.com/saitamanodoruji/4950258/raw/tumblrtagcommand.user.js | |
// @downloadURL https://gist.github.com/saitamanodoruji/4950258/raw/tumblrtagcommand.user.js | |
// ==/UserScript== | |
// origin: | |
// http://userscripts.org/scripts/show/56547 | |
// 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 = ',' | |
const FETCH_URL = 'http://www.tumblr.com/svc/post/fetch' | |
const UPDATE_URL = 'http://www.tumblr.com/svc/post/update' | |
const DASHBOARD_URL = 'http://www.tumblr.com/dashboard' | |
var boot = function() { | |
var $X = sharedObject.Minibuffer.$X | |
var D = sharedObject.Minibuffer.D | |
var createDocumentFromString = sharedObject.Minibuffer.createDocumentFromString | |
// ---------------------------------------------------------------------------- | |
// Tumblr Tag | |
// ---------------------------------------------------------------------------- | |
var parseTagList = function(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+$/, '') | |
} | |
} | |
var isTumblrDashboardURL = function(url) { | |
return url.match(/^http:\/\/www\.tumblr\.com\/(?:dashboard|blog|show|likes|liked\/by|tagged)/) ? true : false | |
} | |
var isTumblrUserURL = function(url) { | |
return url.match(/^https?:\/\/[^.]+\.tumblr\.com\/post\/(\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\/(\d+)/)) ? true : false | |
} | |
// copy from tombloo | |
var unescapeHTML = function(s) { | |
return s.replace(/"/g, '"') | |
.replace(/</g, '<') | |
.replace(/>/g, '>') | |
.replace(/&/g, '&') | |
} | |
var getPIDAndChannelID = function(url) { | |
url = unescapeHTML(url) | |
if (/&pid=([^&]*)&.*&name=([^&"]*)/.test(url)) | |
return { | |
post_id: RegExp.$1, | |
channel_id: RegExp.$2 | |
} | |
} | |
var createToken = function(doc) { | |
var tumblr_ctrls = doc.querySelector('#tumblr_controls') | |
if (tumblr_ctrls) { return getPIDAndChannelID(tumblr_ctrls.src) } | |
} | |
var getTokenFromPermalink = function(url) { | |
var d = D(), | |
gtfpd = d.xhttp.get(url). | |
next(function(res) { | |
var doc = createDocumentFromString(res.responseText) | |
return createToken(doc) | |
}). | |
error(function(e) { | |
var message = e.message || e | |
if (confirm(message + '\nfailed to get reblog key.\nopen the post page ? \n' + url)) | |
GM_openInTab(url, true) | |
}) | |
return gtfpd | |
} | |
var createUpdateData = function(res_fetch, token) { | |
var data_update = { | |
form_key: token.form_key, | |
channel_id: token.channel_id, | |
post_id: token.post_id, | |
edit: true, | |
silent: true, | |
context_id: '' | |
} | |
for (var n in res_fetch) { data_update[n] = res_fetch[n] } | |
for (var n in data_update.post) { data_update['post[' + n + ']'] = data_update.post[n] } | |
data_update['post[state]'] = data_update['post[state]'].toString() | |
if (data_update.post.type == 'photo') { | |
// photos | |
data_update.MAX_FILE_SIZE = '10485760' | |
if (data_update.post.photos && data_update.post.photos.length) { | |
var photoset_order = [] | |
data_update.post.photos.forEach(function(p) { | |
data_update['images[' + p.id + ']'] = '' | |
photoset_order.push(p.id) | |
}) | |
data_update['post[photoset_order]'] = photoset_order.join(',') | |
} | |
delete data_update.post | |
} else if (data_update.post.type == 'audio') { | |
// audios | |
data_update.album_art = data_update.post.audio_artwork | |
data_update.pre_upload = '' | |
data_update.preupload_url = '' | |
data_update.remove_album_art = '' | |
data_update.MAX_FILE_SIZE = '10485760' | |
for (var n in data_update['post[id3_tags]']) { | |
data_update['id3_tags[' + n.toLowerCase() + ']'] = data_update['post[id3_tags]'][n] | |
} | |
} else if (data_update.post.type == 'video') { | |
// videos | |
data_update.pre_upload = '' | |
data_update.preupload_url = '' | |
data_update.preupload_ch = '' | |
data_update.MAX_FILE_SIZE = '10485760' | |
if (data_update.post.is_direct_video == false) { | |
data_update.valid_embed_code = '1' | |
} else if (data_update.post.is_direct_video == true) { | |
data_update.valid_embed_code = '' | |
data_update.keep_video = '1' | |
} | |
} | |
return data_update | |
} | |
var getTokens = function(stdin, deferred, message) { | |
var getTokensd | |
if (isTumblrDashboardURL(window.location.href) | |
&& stdin.every(function(s) { return s.nodeName == 'DIV' })) { | |
getTokensd = deferred.next(function() { | |
var tokens = {} | |
stdin.forEach(function(s, i) { | |
tokens[i] = { | |
post_id: s.getAttribute('data-post-id'), | |
channel_id: s.getAttribute('data-tumblelog-name') || | |
document.querySelector('#search_form input[name="t"]').value | |
} | |
sharedObject.Minibuffer.status(COMMAND_TAG + tokens[i].post_id, message) | |
}) | |
return tokens | |
}) | |
} else if (isTumblrUserURL(window.location.href) && !stdin.length) { | |
var tokens = { 0: createToken(document)} | |
sharedObject.Minibuffer.status(COMMAND_TAG + tokens[0].post_id, message) | |
getTokensd = deferred.next(function() { return tokens }) | |
} else { | |
var urls = [] | |
if (stdin.every(function(s) { return s.nodeName == 'A' } )) { | |
// pinned-or-current-link | |
urls = stdin.map(function(s) { return s.href }) | |
} else if (stdin.every(function(s) { return typeof s == 'string' })) { | |
// location | |
urls = stdin | |
} | |
urls = urls.filter(isTumblrUserURL) | |
urls.forEach(function(url) { | |
sharedObject.Minibuffer.status(COMMAND_TAG + url.match(/\/post\/(\d+)/)[1], message) | |
}) | |
getTokensd = deferred.parallel(urls.map(getTokenFromPermalink)) | |
} | |
return getTokensd | |
} | |
var getFormKey = function(deferred, tokens) { | |
var getFormKeyd | |
if(isTumblrDashboardURL(window.location.href)) { | |
getFormKeyd = deferred.next(function() { | |
return document.body.getAttribute('data-form-key') | |
}) | |
} else { | |
getFormKeyd = deferred.next(function() { | |
return deferred.xhttp.get(DASHBOARD_URL) | |
}). | |
next(function(res) { | |
return res.responseText.match(/data-form-key="([^"]+)"/)[1] | |
}). | |
error(function(e) { | |
var message = e.message || e | |
edit_urls = tokens.map(function(t) { | |
return 'http://www.tumblr.com/edit/' + t.post_id + '?redirect_to=%2Fdashboard%2F2%2F' + (parseInt(t.post_id) + 1) | |
}) | |
if (confirm(message + '\nfailed to get form_key.\nedit ' + tokens.length + ' post(s) manually ? \n' + edit_urls.join('\n'))) { | |
edit_urls.forEach(function(url) { GM_openInTab(url, true) }) | |
} | |
}) | |
} | |
return getFormKeyd | |
} | |
var edit = function(token, form_key, appends, removes, message) { | |
token.form_key = form_key | |
var d = sharedObject.Minibuffer.D(), | |
editd = d.xhttp.post(FETCH_URL, JSON.stringify(token)). | |
next(function(res) { | |
if (res.status == 200) { | |
if (!res.finalUrl.match(/^http:\/\/www\.tumblr\.com\/svc\/post\/fetch/)) { | |
return editd.fail('unexpected response (fetch): ' + res.finalUrl) | |
} else { | |
var res_fetch = JSON.parse(res.responseText), | |
data_update = createUpdateData(res_fetch, token) | |
if (data_update['post[tags]'] === null) { | |
data_update['post[tags]'] = appends.join(SEPARATOR) | |
} else { | |
data_update['post[tags]'] = parseTagList(data_update['post[tags]']).concat(appends).remove(removes).uniq().join(SEPARATOR) | |
} | |
return d.xhttp.post(UPDATE_URL, JSON.stringify(data_update)) | |
} | |
} else { | |
return editd.fail(res.status + ' in adding tag (fetch)') | |
} | |
}). | |
next(function(res) { | |
if (res.status == 200) { | |
if (!res.finalUrl.match(/^http:\/\/www\.tumblr\.com\/svc\/post\/update/)) { | |
return editd.fail('unexpected response (update): ' + res.finalUrl) | |
} else { | |
sharedObject.Minibuffer.status(COMMAND_TAG + token.post_id, message + ' ... done.', 100) | |
} | |
} else { | |
return editd.fail(res.status + ' in adding tag (update)') | |
} | |
}). | |
error(function(e) { | |
var mes = 'error: ', | |
edit_url = 'http://www.tumblr.com/edit/' + token.post_id + '?redirect_to=%2Fdashboard%2F2%2F' + (parseInt(token.post_id) + 1) | |
sharedObject.Minibuffer.status(COMMAND_TAG + token.post_id, message + ' ... error.', 100) | |
if (typeof(e) == 'object') { | |
var arr = [e.message] | |
for (var n in e) { arr.push(n + ' = ' + e[n]) } | |
mes += arr.join('\n') | |
} else { mes += e } | |
if (confirm(mes + '\nedit manually ? \n' + edit_url)) { | |
GM_openInTab(edit_url, true) | |
} | |
}) | |
return d | |
} | |
// ---------------------------------------------------------------------------- | |
// Command | |
// ---------------------------------------------------------------------------- | |
var getTargetCommand = function() { | |
var target_cmd = '' | |
if (isTumblrDashboardURL(window.location.href)) { | |
target_cmd = 'pinned-or-current-node' | |
} else if (!isTumblrUserURL(window.location.href)) { | |
target_cmd = 'pinned-or-current-link' | |
} | |
return target_cmd | |
} | |
sharedObject.Minibuffer.addShortcutkey({ | |
key: KEY_TAG, | |
description: 'Tag Tumblr posts', | |
command: function() { | |
var target_cmd = getTargetCommand(), | |
clear_pin = '', | |
tags = prompt('Input new tags and the tags to be deleted.\n(ex. To add \'picture\' and remove \'pict\', use \'picture,-pict\'.)') | |
if (target_cmd != '') target_cmd = target_cmd + ' | ' | |
clear_pin = (/^pinned-or-current-(?:node|link) | $/.test(target_cmd)) ? ' | clear-pin' : '' | |
sharedObject.Minibuffer.execute(target_cmd + [COMMAND_TAG, tags].join(' ') + clear_pin) | |
} | |
}) | |
sharedObject.Minibuffer.addShortcutkey({ | |
key: KEY_TAG_ALL, | |
description: 'Tag all Tumblr posts in screen', | |
command: function() { | |
var target_cmd = isTumblrDashboardURL(window.location.href) ? 'all-node' : 'tumblr-posts', | |
tags = prompt('Input new tags and the tags to be deleted.\n(ex. To add \'picture\' and remove \'pict\', use \'picture,-pict\'.)') | |
sharedObject.Minibuffer.execute(target_cmd + ' | '+[COMMAND_TAG, tags].join(' ')) | |
} | |
}) | |
sharedObject.Minibuffer.addCommand({ | |
name: COMMAND_POSTS, | |
command: function(stdin) { | |
var linkx = sharedObject.LDRize.getSiteinfo().link, | |
parax = sharedObject.LDRize.getSiteinfo().paragraph, | |
getfirst = function(x) { return x[0] != undefined ? x[0] : x }, | |
items = $X(parax).map(function(i){ return getfirst($X(linkx, i)) }) | |
return items | |
} | |
}) | |
sharedObject.Minibuffer.addCommand({ | |
name: COMMAND_TAG, | |
command: function(stdin) { | |
if (!stdin.length) { | |
if (isTumblrDashboardURL(window.location.href.toString())) { | |
stdin = sharedObject.Minibuffer.execute('pinned-or-current-node') | |
} else if (!isTumblrUserURL(window.location.href.toString())) { | |
stdin = sharedObject.Minibuffer.execute('pinned-or-current-link') | |
} | |
} | |
// edit tags | |
var args = parseTagList(this.args.join(' ')) | |
if (args.length == 0) { | |
sharedObject.Minibuffer.status(COMMAND_TAG, 'No tag is specified', 1000) | |
return null | |
} | |
var appends = [], removes = [], message = '', tokens = [] | |
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() | |
if (appends.length > 0) { | |
message += 'Adding '+appends.join(SEPARATOR) | |
} | |
if (removes.length > 0) { | |
message += (message.length > 0 ? ', removing ': 'Removing ') + removes.join(SEPARATOR) | |
} | |
var deferred = sharedObject.Minibuffer.D() | |
var tagd = deferred.next(function() { | |
return getTokens(stdin, deferred, message) | |
}). | |
next(function(values) { | |
for (var i in values) { tokens[i] = values[i] } | |
if (tokens.length > 1) sharedObject.Minibuffer.status(COMMAND_TAG, 'Everything is OK', 1000) | |
return getFormKey(deferred, tokens) | |
}). | |
next(function(form_key) { | |
deferred.parallel(tokens.map(function(token) { | |
return edit(token, form_key, appends, removes, message) | |
})) | |
}). | |
error(function(e) { | |
var message = [e.message || e] | |
if (typeof(e) == 'object') { | |
for ( var n in e ) { message.push(n + ': ' + e[n]) } | |
} | |
alert(message.join('\n')) | |
}) | |
return stdin | |
} | |
}) | |
} | |
if (sharedObject.Minibuffer) { | |
boot() | |
} else { | |
window.addEventListener('GM_MinibufferLoaded', boot, false) | |
} | |
})() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment