「CShellExt::QueryContextMenu」でやれば出来なく無いけどコストがデカイし別のシェルエクステンション混ぜると落ちたりするんですよね。
Gyazowin tumblr for Windowsにファイルのアップロード機能を追加して名前をGyamblr for Windowsに変更 « ZeroMemory本当は「CShellExt::QueryContextMenu」でやるのがいいんだろうけど、今回はコマンドラインユーザでも使える様にコマンド形式で「送る」に登録する方法にした。
Windowsのコンテキストメニューのコピーとかにcopy to tumblrみたいなのを追加できないかなと思ったんだけど、標準のやつはともかくアプリケーションの右クリックはアプリケーション管轄で制御されていてWindowsシロウト同然の自分には外からいじれなそうだったのであきらめました。
動作させる為にはpythonが必要。
pythonをインストールしたら、以下のソースを「tumblr_post.py」として保存する。
import os, sys
import re, getopt, glob
import urllib, urllib2
import mimetypes
settings = {}
supported_encodings = ['ms932', 'utf-8', 'euc-jp', 'iso-2022-jp']
class Callable:
def __init__(self, anycallable):
self.__call__ = anycallable
class MultipartPostHandler(urllib2.BaseHandler):
handler_order = urllib2.HTTPHandler.handler_order - 10
def http_request(self, request):
data = request.get_data()
if data is not None and type(data) != str:
v_files = []
v_vars = []
try:
for(key, value) in data.items():
if type(value) == file:
v_files.append((key, value))
else:
v_vars.append((key, value))
except TypeError:
systype, value, traceback = sys.exc_info()
raise TypeError, "not a valid non-string sequence or mapping object", traceback
if len(v_files) == 0:
data = urllib.urlencode(v_vars, 1)
else:
boundary, data = self.multipart_encode(v_vars, v_files)
contenttype = 'multipart/form-data; boundary=%s' % boundary
if request.has_header('Content-type'):
pass
request.add_unredirected_header('Content-type', contenttype)
request.add_data(data)
return request
def multipart_encode(vars, files, boundary = None, buffer = None):
if boundary is None:
boundary = mimetools.choose_boundary()
if buffer is None:
buffer = ''
for(key, value) in vars:
buffer += '--%s\r\n' % boundary
buffer += 'Content-Disposition: form-data; name="%s"' % key
buffer += '\r\n\r\n' + value + '\r\n'
for(key, fd) in files:
file_size = os.fstat(fd.fileno())[stat.ST_SIZE]
filename = fd.name.split('/')[-1]
contenttype = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
buffer += '--%s\r\n' % boundary
buffer += 'Content-Disposition: form-data; name="%s"; filename="%s"\r\n' % (key, filename)
buffer += 'Content-Type: %s\r\n' % contenttype
fd.seek(0)
buffer += '\r\n' + fd.read() + '\r\n'
buffer += '--%s--\r\n\r\n' % boundary
return boundary, buffer
multipart_encode = Callable(multipart_encode)
https_request = http_request
def post_object(object, type=None):
fields = {
'email': settings['usermail'],
'password': settings['password'],
'private': settings['private'],
'type': 'regular'
}
types = {
'audio': 'audio',
'video': 'video',
'application': None,
}
if type:
fields['type'] = type['type']
fields[type['key']] = object
else:
mime = mimetypes.guess_type(object)[0]
if not mime:
raise RuntimeError('unknown content type of "%s"' % object)
reg = re.compile('^([^/]+)/')
m = reg.search(mime)
if m.group(1) == 'text':
fields['type'] = 'quote'
fields['quote'] = open(object, 'rb').read()
for encoding in supported_encodings:
try:
fields['quote'] = fields['quote'].decode(encoding).encode('utf-8')
break
except UnicodeError:
continue
elif m.group(1) == 'image':
fields['type'] = 'photo'
fields['data'] = open(object, 'rb').read()
else:
fields['type'] = types[m.group(1)]
fields['data'] = open(object, 'rb').read()
if not fields['type']:
raise RuntimeError('unknown content type of "%s"' % object)
u = None
try:
opener = urllib2.build_opener(MultipartPostHandler)
u = opener.open('http://www.tumblr.com/api/write', fields)
u.read()
except urllib2.HTTPError, e:
if e.code != 201: raise e
finally:
if u: u.close()
return fields['type'], object
def load_config():
file = None
try:
file = open(os.path.expanduser('~/.tumblr_post'), 'r')
reg = re.compile('^([^=]+)=(\S*)$')
while True:
line = file.readline()
if not line: break
if line == '\n': continue
m = reg.search(line)
settings[m.group(1)] = m.group(2)
finally:
if (file): file.close()
def main(argv):
try:
opts, args = getopt.gnu_getopt(sys.argv[1:], "rs")
except getopt.GetoptError:
print 'usage: %s [files ...]' % argv[0]
return -1
load_config()
for arg in args:
if re.compile('^http[s]*://').match(arg):
type, object = post_object(arg, {'type': 'link', 'key': 'url'})
print 'posted "%s" as %s' % (object, type)
else:
for file in glob.glob(arg):
type, object = post_object(file)
print 'posted "%s" as %s' % (object, type)
return 0
if __name__ == '__main__': sys.exit(main(sys.argv))
保存先は何処でも良いけど例として
C:¥tumblr_post¥tumblr_post.py
にしておく。次に「C:¥Python25¥pythonw.exe」(python.exeでなくpythonw.exe)のショートカットを作り、ショートカットのプロパティで「リンク先」を
C:¥Python25¥pythonw.exe
から
C:¥Python25¥pythonw.exe C:¥tumblr_post¥tumblr_post.py
に変更する。そして「アイコンの変更」をクリックしてtumblrのロゴアイコン- http://assets.tumblr.com/images/favicon.gifを適当なfavicon生成サイトで変換したicoファイルに設定する。
後はこのショートカットを
C:¥Documents and Settings¥貴方のアカウント¥SendTo¥
にコピーすれば完成!このツールには設定ファイルが必要で
C:¥Documents and Settings¥貴方のアカウント¥.tumblr_post
というファイルを作る必要があります。中身は
usermail=your.name@your.email.com
password=your-password
private=0
といった感じ。「private=1」にすると非公開になりますから、tumblr著作権ウゼーーという方は、この設定でアップするのが良いかと。
なお、このツールは
- 画像
- 動画
- 音声
- テキスト
- リンク
コマンドラインからの操作に限り
C:¥> tumblr_post.py http://www.tumblr.com/
といった使い方が出来る様になっています。pythonなのでun*xでも使えます。殆どtumblr使ってない私ですが、よろしければどうぞ。
Enjoy!