Skip to content

Instantly share code, notes, and snippets.

@poochin
Last active December 11, 2015 18:39
Show Gist options
  • Save poochin/4643227 to your computer and use it in GitHub Desktop.
Save poochin/4643227 to your computer and use it in GitHub Desktop.
// Tumblr reblogフォームの変更により対応(中)のパッチ
// photoでテストしてて http://www.tumblr.com/svc/post/update で403が返ってくる途中の状態
// あと fetchが重い(というかfetchの必要ない(?)
(function() {
update(Tombloo.Service.extractors['ReBlog - Dashboard'], {
extract : function(ctx) {
return Tombloo.Service.extractors.ReBlog.extractByLink(ctx, this.getLink(ctx)).addCallback(function(res) {
var expr = './ancestor-or-self::li[starts-with(normalize-space(@class), "post")]' +
'//a[starts-with(@href,"/reblog/")]';
if (!res.type) {
res.type = $x(expr + '/@data-post-type', ctx.target);
}
if (res.favorite) {
res.favorite.form || (res.favorite.form = {});
update(res.favorite.form, {
id : $x(expr + '/@data-reblog-id', ctx.target),
key : $x(expr + '/@data-reblog-key', ctx.target),
form_key : $x(expr + '/@data-user-form-key', ctx.target)
});
}
return res;
});
}
});
addAround(Tumblr, 'favor', function(proceed, args) {
var ps = args[0];
return requestJSON('http://www.tumblr.com/svc/post/fetch', {
sendContent : JSON.stringify({
form_key : ps.favorite.form.form_key,
post_type : false,
reblog_id : ps.favorite.form.id,
reblog_key : ps.favorite.form.key
})
}).addErrback(function(err) {debug(err)}).addCallback(function(res) {
var key, params = {}, data = JSON.parse(res.responseText);
for (key in data) {
if (typeof data[key] !== 'object') {
params[key] = data[key];
}
}
for (key in data.post) {
params['post[' + key + ']'] = data.post[key];
}
params = update({
detached : true,
reblog : true,
reblog_id : ps.favorite.form.id,
reblog_key : ps.favorite.form.key,
reblog_post_id : ps.favorite.form.id,
form_key : ps.favorite.form.form_key,
silent : true,
channel_id : '', //TOOD: username
context_id : ''
}, params);
params['post[draft_status]'] = '';
params['post[state]'] = '0';
return requestJSON('http://www.tumblr.com/svc/post/update', {
method: 'post',
headers : {
'Content-Type' : 'application/json'
},
sendContent : JSON.stringify(params)
});
})./* for debug */addErrback(function(res) { debug(res) });
});
/**
* Tombloo 01_utility.js request() の拡張
*/
function requestJSON(url, opts, isMultipart) {
var d = new Deferred();
var contentType;
opts = opts || {};
var uri = createURI(joinText([url, queryString(opts.queryString)], '?'));
let channel = broad(IOService.newChannelFromURI(uri), [Ci.nsIUploadChannel, IHttpChannel]);
if (opts.referrer) {
channel.referrer = createURI(opts.referrer);
}
if (opts.headers) {
items(opts.headers).forEach(function([key, value]) {
if (/^Content-?Type$/i.test(key)) {
channel.contentType = contentType = value;
}
channel.setRequestHeader(key, value, true);
});
}
setCookie(channel);
if (opts.sendContent) {
var contents = opts.sendContent;
if (!isMultipart) {
contents = (typeof contents === 'string') ? contents : queryString(contents);
channel.setUploadStream(
new StringInputStream(contents),
contentType || 'application/x-www-form-urlencoded', -1);
} else {
var boundary = '---------------------------' + (new Date().getTime());
var streams = [];
for (var name in contents) {
var value = contents[name];
if (value == null) {
continue;
}
if (!value.file) {
streams.push([
'--' + boundary,
'Content-Disposition: form-data; name="' + name + '"',
'',
value.convertFromUnicode? value.convertFromUnicode() : value,
]);
} else {
if (value.file instanceof IFile) {
value.contentType = value.contentType || getMimeType(value.file);
value.fileName = value.file.leafName;
value.file = IOService.newChannelFromURI(createURI(value.file)).open();
}
streams.push([
'--' + boundary,
'Content-Disposition: form-data; name="' + name + '"; filename="' + (value.fileName || '_') + '"',
'Content-Type: ' + (value.contentType || 'application/octet-stream'),
'',
])
streams.push(new BufferedInputStream(value.file));
streams.push('');
}
}
streams.push('--' + boundary + '--');
var mimeStream = new MIMEInputStream(new MultiplexInputStream(streams));
mimeStream.addHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);
channel.setUploadStream(mimeStream, null, -1);
}
}
var redirectionCount = 0;
var listener = {
QueryInterface : createQueryInterface([
'nsIStreamListener',
'nsIProgressEventSink',
'nsIHttpEventSink',
'nsIInterfaceRequestor',
'nsIChannelEventSink']),
isAppOfType : function(val) {
return (val == 0);
},
onProgress : function(req, ctx, progress, progressMax) {},
onStatus : function(req, ctx, status, statusArg) {},
getInterface : function(iid) {
try {
return this.QueryInterface(iid);
} catch(e) {
throw Cr.NS_NOINTERFACE;
}
},
onRedirect : function(oldChannel, newChannel) {},
onRedirectResult: function(){},
asyncOnChannelRedirect : function(oldChannel, newChannel, flags, redirectCallback) {
this.onChannelRedirect(oldChannel, newChannel, flags);
redirectCallback.onRedirectVerifyCallback(0);
},
onChannelRedirect : function(oldChannel, newChannel, flags) {
redirectionCount++;
if(opts.redirectionLimit != null && redirectionCount > opts.redirectionLimit) {
newChannel.cancel(2152398879);
var res = {
channel : newChannel,
responseText : '',
status : oldChannel.responseStatus,
statusText : oldChannel.responseStatusText
};
d.callback(res);
return;
}
broad(oldChannel);
if(oldChannel.requestMethod == 'HEAD') {
broad(newChannel);
newChannel.requestMethod = 'HEAD';
}
setCookie(newChannel);
},
onStartRequest: function(req, ctx) {
this.data = [];
},
onDataAvailable: function(req, ctx, stream, sourceOffset, length) {
this.data.push(new InputStream(stream).read(length));
},
onStopRequest: function (req, ctx, status) {
if (opts.redirectionLimit != null && redirectionCount > opts.redirectionLimit) {
return;
}
broad(req);
var text = this.data.join('');
try {
var charset = opts.charset || req.contentCharset || text.extract(/content=["'].*charset=(.+?)[;"']/i);
text = charset? text.convertToUnicode(charset) : text;
var res = {
channel : req,
responseText : text,
status : req.responseStatus,
statusText : req.responseStatusText,
};
} catch(e) {
var res = {
channel : req,
responseText : text,
status : null,
statusText : null
};
}
if (Components.isSuccessCode(status) && res.status < 400) {
d.callback(res);
} else {
error(res);
res.message = getMessage('error.http.' + res.status);
d.errback(res);
}
}
};
channel.requestMethod = (opts.method) ? opts.method :
(opts.sendContent) ? 'POST' : 'GET';
channel.notificationCallbacks = listener;
channel.asyncOpen(listener, null);
broad(channel);
listener = null;
channel = null;
return d;
}
}());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment