| 1 | // ==UserScript== |
|---|
| 2 | // @name ReblogCommand |
|---|
| 3 | // @namespace http://white.s151.xrea.com/ |
|---|
| 4 | // @include http://* |
|---|
| 5 | // @include https://* |
|---|
| 6 | // @exclude http://www.tumblr.com/share |
|---|
| 7 | // ==/UserScript== |
|---|
| 8 | |
|---|
| 9 | (function() { |
|---|
| 10 | |
|---|
| 11 | const ALLOW_OWN_DOMAIN = true; |
|---|
| 12 | |
|---|
| 13 | var boot = function() { |
|---|
| 14 | var $X = window.Minibuffer.$X; |
|---|
| 15 | var D = window.Minibuffer.D; |
|---|
| 16 | var createDocumentFromString = window.Minibuffer.createDocumentFromString; |
|---|
| 17 | |
|---|
| 18 | // ---------------------------------------------------------------------------- |
|---|
| 19 | // Reblog |
|---|
| 20 | // ---------------------------------------------------------------------------- |
|---|
| 21 | |
|---|
| 22 | function isTumblrDashboardURL(url) { |
|---|
| 23 | return url.match("^http://www\\.tumblr\\.com/dashboard") ? true : false; |
|---|
| 24 | } |
|---|
| 25 | |
|---|
| 26 | function isTumblrUserURL(url) { |
|---|
| 27 | return url.match("^https?://[^.]+\\.tumblr\\.com/post/(\\d+)") || |
|---|
| 28 | // tumblr allow to use own domain. but this is risky. |
|---|
| 29 | // $X('id("tumblr_controls")[self::iframe]', Boolean) |
|---|
| 30 | (ALLOW_OWN_DOMAIN && url.match("^https?://[^/]+/post/(\\d+)")) ? true : false; |
|---|
| 31 | } |
|---|
| 32 | |
|---|
| 33 | function isLdrOrFldrURL(url) { |
|---|
| 34 | return url.indexOf('http://reader.livedoor.com/reader/') == 0 || |
|---|
| 35 | url.indexOf('http://reader.livedoor.com/public/') == 0 || |
|---|
| 36 | url.indexOf('http://fastladder.com/reader/') == 0 || |
|---|
| 37 | url.indexOf('http://fastladder.com/public/') == 0; |
|---|
| 38 | } |
|---|
| 39 | |
|---|
| 40 | function getIDByPermalink(url) { |
|---|
| 41 | if (isTumblrUserURL(url)) { |
|---|
| 42 | return RegExp.$1; |
|---|
| 43 | } |
|---|
| 44 | // return what ? |
|---|
| 45 | return false; |
|---|
| 46 | } |
|---|
| 47 | |
|---|
| 48 | function getURLByID(id, token) { |
|---|
| 49 | if (token) return "http://www.tumblr.com/reblog/" + id + "/" + token + "?redirect_to=/dashboard"; |
|---|
| 50 | return "http://www.tumblr.com/reblog/" + id; |
|---|
| 51 | } |
|---|
| 52 | |
|---|
| 53 | // copy from tombloo |
|---|
| 54 | function unescapeHTML(s) { |
|---|
| 55 | return s.replace(/"/g, '"') |
|---|
| 56 | .replace(/</g, '<') |
|---|
| 57 | .replace(/>/g, '>') |
|---|
| 58 | .replace(/&/g, '&'); |
|---|
| 59 | } |
|---|
| 60 | |
|---|
| 61 | // copy from tombloo |
|---|
| 62 | function getReblogToken(url) { |
|---|
| 63 | url = unescapeHTML(url); |
|---|
| 64 | if (/&pid=([^&]*)&rk=([^&"]*)/.test(url) || /\/reblog\/([^\/]+)\/([^?]*)/.test(url)) |
|---|
| 65 | return { |
|---|
| 66 | id : RegExp.$1, |
|---|
| 67 | token : RegExp.$2 |
|---|
| 68 | }; |
|---|
| 69 | } |
|---|
| 70 | |
|---|
| 71 | function parseParams(doc) { |
|---|
| 72 | // name() returns in lower case on fx3.6 |
|---|
| 73 | var elms = $X('id("edit_post")//*[translate(name(),"input", "INPUT") ="INPUT" or translate(name(),"textarea", "TEXTAREA")="TEXTAREA" or translate(name(),"select", "SELECT")="SELECT"]', doc); |
|---|
| 74 | var params = {}; |
|---|
| 75 | elms.forEach(function(elm) { |
|---|
| 76 | params[elm.name] = elm.value; |
|---|
| 77 | }); |
|---|
| 78 | return params; |
|---|
| 79 | } |
|---|
| 80 | |
|---|
| 81 | function createPostData(params) { |
|---|
| 82 | var arr = []; |
|---|
| 83 | for (var param in params) { |
|---|
| 84 | if (param != "preview_post" && param != "send_to_twitter") { |
|---|
| 85 | arr.push(encodeURIComponent(param)); |
|---|
| 86 | arr.push("="); |
|---|
| 87 | arr.push(encodeURIComponent(params[param])); |
|---|
| 88 | arr.push("&"); |
|---|
| 89 | } |
|---|
| 90 | } |
|---|
| 91 | return arr.join(''); |
|---|
| 92 | } |
|---|
| 93 | |
|---|
| 94 | function reblog(aURL) { |
|---|
| 95 | var id = getIDByPermalink(aURL); |
|---|
| 96 | var d; |
|---|
| 97 | with (D()) { |
|---|
| 98 | d = Deferred(); |
|---|
| 99 | if (!id) { |
|---|
| 100 | wait(0).next(function() { d.call(); }); |
|---|
| 101 | return d; |
|---|
| 102 | } |
|---|
| 103 | } |
|---|
| 104 | window.Minibuffer.status('ReblogCommand'+id, 'Reblog ...'); |
|---|
| 105 | d = D(); |
|---|
| 106 | var url = aURL; |
|---|
| 107 | var reblogd = d.xhttp.get(url). |
|---|
| 108 | next(function(res) { |
|---|
| 109 | var token = getReblogToken(res.responseText.match('iframe src="((?:\\"|[^"])*)"')[1]); |
|---|
| 110 | url = getURLByID(token.id, token.token); |
|---|
| 111 | return d.xhttp.get(url); |
|---|
| 112 | }). |
|---|
| 113 | next(function(res) { |
|---|
| 114 | var params = parseParams( createDocumentFromString(res.responseText)); |
|---|
| 115 | if (!params.form_key) |
|---|
| 116 | reblogd.fail("invalid reblog params."); |
|---|
| 117 | return d.xhttp.post(url, createPostData(params)); |
|---|
| 118 | }). |
|---|
| 119 | next(function(res) { |
|---|
| 120 | if ( ! res.finalUrl.match( /^http:\/\/www\.tumblr\.com\/dashboard/ ) ) |
|---|
| 121 | reblogd.fail("reblog failed."); |
|---|
| 122 | window.Minibuffer.status('ReblogCommand'+id, 'Reblog ... done.', 100); |
|---|
| 123 | d.call(); |
|---|
| 124 | }). |
|---|
| 125 | error(function(e) { |
|---|
| 126 | var message = e.message || e; |
|---|
| 127 | if (confirm(message + '\nreblog manually ? \n' + url)) reblogManually(url); |
|---|
| 128 | d.call(); |
|---|
| 129 | }); |
|---|
| 130 | return d; |
|---|
| 131 | } |
|---|
| 132 | |
|---|
| 133 | function reblogManually(aURL) { |
|---|
| 134 | var url = aURL; |
|---|
| 135 | var d = D(); |
|---|
| 136 | d.xhttp.get(url). |
|---|
| 137 | next(function(res) { |
|---|
| 138 | var token = getReblogToken(res.responseText.match('iframe src="((?:\\"|[^"])*)"')[1]); |
|---|
| 139 | url = getURLByID(token.id, token.token); |
|---|
| 140 | GM_openInTab(url); |
|---|
| 141 | }); |
|---|
| 142 | } |
|---|
| 143 | |
|---|
| 144 | function spClearPins(url) { |
|---|
| 145 | unsafeWindow.pin.remove(url); |
|---|
| 146 | } |
|---|
| 147 | |
|---|
| 148 | // ---------------------------------------------------------------------------- |
|---|
| 149 | // Command |
|---|
| 150 | // ---------------------------------------------------------------------------- |
|---|
| 151 | |
|---|
| 152 | function getTargetCommand() { |
|---|
| 153 | var target_cmd = ''; |
|---|
| 154 | if (isLdrOrFldrURL(window.location.href)) { |
|---|
| 155 | target_cmd = 'pinned-or-current-link'; |
|---|
| 156 | } else if (isTumblrUserURL(window.location.href)) { |
|---|
| 157 | target_cmd = 'location'; |
|---|
| 158 | } else if (window.LDRize) { |
|---|
| 159 | target_cmd = 'pinned-or-current-link'; |
|---|
| 160 | } else { |
|---|
| 161 | target_cmd = 'location'; |
|---|
| 162 | } |
|---|
| 163 | return target_cmd; |
|---|
| 164 | } |
|---|
| 165 | |
|---|
| 166 | window.Minibuffer.addShortcutkey({ |
|---|
| 167 | key: 't', |
|---|
| 168 | description: 'Reblog', |
|---|
| 169 | command: function() { |
|---|
| 170 | var target_cmd = getTargetCommand(); |
|---|
| 171 | var clear_pin = ''; |
|---|
| 172 | if (isLdrOrFldrURL(window.location.href)) { |
|---|
| 173 | if (!window.Minibuffer.execute('pinned-or-current-link').filter(isTumblrUserURL).length) { |
|---|
| 174 | target_cmd = 'current-link'; |
|---|
| 175 | clear_pin = ''; |
|---|
| 176 | } else { |
|---|
| 177 | clear_pin = '-c'; |
|---|
| 178 | } |
|---|
| 179 | } else { |
|---|
| 180 | clear_pin = (target_cmd == 'pinned-or-current-link') ? ' | clear-pin' : ''; |
|---|
| 181 | } |
|---|
| 182 | window.Minibuffer.execute(target_cmd + ' | reblog ' + clear_pin); |
|---|
| 183 | }}); |
|---|
| 184 | |
|---|
| 185 | window.Minibuffer.addShortcutkey({ |
|---|
| 186 | key: 'T', |
|---|
| 187 | description: 'Reblog manually', |
|---|
| 188 | command: function() { |
|---|
| 189 | var target_cmd = getTargetCommand(); |
|---|
| 190 | var clear_pin = (target_cmd == 'pinned-or-current-link') ? ' | clear-pin' : ''; |
|---|
| 191 | window.Minibuffer.execute(target_cmd + ' | reblog -m' + clear_pin ); |
|---|
| 192 | }}); |
|---|
| 193 | |
|---|
| 194 | window.Minibuffer.addCommand({ |
|---|
| 195 | name: 'reblog', |
|---|
| 196 | command: function(stdin) { |
|---|
| 197 | var args = this.args; |
|---|
| 198 | var urls = []; |
|---|
| 199 | if (!stdin.length) { |
|---|
| 200 | if (isTumblrDashboardURL(window.location.href.toString())) { |
|---|
| 201 | var link = window.Minibuffer.execute('current-link'); |
|---|
| 202 | if (link) urls = [link.toString()]; |
|---|
| 203 | } else { |
|---|
| 204 | // command line is just 'reblog' |
|---|
| 205 | urls = [window.location.href]; |
|---|
| 206 | } |
|---|
| 207 | } else if (isLdrOrFldrURL(window.location.href)) { |
|---|
| 208 | var tmp = []; |
|---|
| 209 | stdin.forEach(function(url, index) { tmp[index] = url; }); |
|---|
| 210 | urls = tmp; |
|---|
| 211 | } else if (stdin.every(function(a) { return typeof a == 'string' })) { |
|---|
| 212 | // command line is 'location | reblog' |
|---|
| 213 | urls = stdin; |
|---|
| 214 | } else if (stdin.every(function(a) { return a && a.nodeName == 'A'; })) { |
|---|
| 215 | // command line is 'pinned-or-current-link | reblog' |
|---|
| 216 | urls = stdin.map(function(node) { return node.href; }); |
|---|
| 217 | } |
|---|
| 218 | |
|---|
| 219 | // reblog |
|---|
| 220 | if (args.length == 1 && args[0] == '-m') { |
|---|
| 221 | urls.forEach(reblogManually); |
|---|
| 222 | } else { |
|---|
| 223 | urls = urls.filter(isTumblrUserURL); |
|---|
| 224 | if (isLdrOrFldrURL(window.location.href) && args.length == 1 && args[0] == '-c') { |
|---|
| 225 | urls.forEach(spClearPins); |
|---|
| 226 | } |
|---|
| 227 | if (!urls.length) return stdin; |
|---|
| 228 | var lst = urls.map(reblog); |
|---|
| 229 | if (lst.length > 1) { |
|---|
| 230 | with (D()) { |
|---|
| 231 | parallel(lst).wait(2). |
|---|
| 232 | next(function() { window.Minibuffer.status('ReblogCommand','Everything is OK', 1000); }); |
|---|
| 233 | } |
|---|
| 234 | } |
|---|
| 235 | } |
|---|
| 236 | return stdin; |
|---|
| 237 | } |
|---|
| 238 | }); |
|---|
| 239 | }; |
|---|
| 240 | if (document.body.id == 'tinymce') |
|---|
| 241 | return; |
|---|
| 242 | |
|---|
| 243 | if (window.Minibuffer) { |
|---|
| 244 | boot(); |
|---|
| 245 | } else { |
|---|
| 246 | window.addEventListener('GM_MinibufferLoaded', boot, false); |
|---|
| 247 | } |
|---|
| 248 | |
|---|
| 249 | })(); |
|---|