#! /usr/bin/env python
#-*-coding:utf8-*-
# pyshack -- imageshack uploader
# Copyright (c) 2008 knsd <http://knsd.net/contacts>
#
name="pyshack"
# -------
version="0.4.0"
import sys, os, socket
try:
import curses
except:
pass
from random import choice
class ReadingError(Exception):pass
class FormatError(Exception):pass
class Imageshack:
types = {'jpeg':'image/jpeg', 'png':'image/png', 'gif':'image/gif', 'bmp':'image/bmp'}
def __init__(self):
pass
def send(self, image):
boundary = '-' * 16 + ''.join([choice("0123456789") for x in xrange(29)])
if image.type not in self.types.keys():
raise FormatError
second = '--' + boundary + '\r\n'
second+='Content-Disposition: form-data; name="fileupload"; filename="' + image.file + '"\r\n'
second += 'Content-Type: ' + image.type + '\r\n\r\n'
first = 'POST / HTTP/1.1\r\n'
first += 'Host: www.imageshack.us\r\n'
first += 'Connection: close\r\n'
first += 'Content-Type: multipart/form-data; boundary=' + boundary + '\r\n'
first += 'Content-Length:' + str(len(second) + image.datalen + 53) + '\r\n\r\n'
sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.connect(('38.99.77.90', 80))
sock.send(first)
sock.send(second)
f = open(image.file, 'r')
data = f.read()
f.close()
blocklen = image.datalen/100
for blocknum in range(100):
if blocknum != 99:
sock.send(data[blocklen*blocknum:blocklen*(blocknum+1)])
yield ('state', blocknum+1, blocklen*blocknum)
else:
sock.send(data[blocklen*blocknum:])
yield ('state', blocknum+1, image.datalen)
sock.send('\r\n--' + boundary + '--\r\n')
data = ''
buff = sock.recv(1024)
while buff:
data += buff
buff = sock.recv(1024)
sock.close()
link = data.split('<input type="text" onClick="track(\'direct\');highlight(this)"')[1].split('"/>')[0].split('"')[-1]
yield ('link', link)
class Image:
def __init__(self, file):
self.file = file
self.width = None
self.height = None
self.type = None
self.error = None
def check(self):
if not os.access(self.file, os.F_OK):
self.error = 'No such file'
return None
if not os.access(self.file, os.R_OK):
self.error = 'Can not read file'
return None
if not os.path.isfile(self.file):
self.error = 'It is not file'
return None
self.datalen = os.lstat(self.file)[6]
l = [self.png, self.jpeg, self.bmp, self.gif]
for each in l:
try:
self.width, self.height, self.type = each(self.file)
break
except FormatError:
continue
if self.width and self.height and self.type:
return self.width, self.height, self.type
else:
self.error = 'Not supported format'
return None
def get_int(self, s):
n = 0
for each in xrange(len(s)):
n += 256 ** each * ord(s[len(s) - 1 - each])
return n
def png(self, file):
f = open(file, 'r')
if f.read(8) != '\x89PNG\r\n\x1A\n':
f.close()
raise FormatError
f.seek(8, 1)
width = self.get_int(f.read(4))
height = self.get_int(f.read(4))
f.close()
return width, height, 'png'
def jpeg(self, file):
def readMarker(f):
if f.read(1)!='\xff':
f.close()
raise ReadingError
return f.read(1)
f = open(file, 'r')
if f.read(4) not in ("\xff\xd8\xff\xe0", "\xff\xd8\xff\xe1", "\xff\xd8\xff\xee"):
f.close()
raise FormatError
f.seek(0)
for each in range(20):
marker = readMarker(f)
if marker in ['\xc0', '\xc1', '\xc2']:
f.seek(3, 1)
height = self.get_int(f.read(2))
width = self.get_int(f.read(2))
break
elif marker in ('\xe0', '\xe1', '\xe2', '\xe3', '\xe4', '\xe5', '\xe6', '\xe7', '\xe8', '\xe9', '\xea', '\xeb', '\xec', '\xee', '\xef', '\xdb', '\xed', '\xfe', '\xc4'):
skip = (ord(f.read(1))<<8)+ord(f.read(1))
f.seek(skip-2, 1)
f.close()
return width, height, 'jpeg'
def bmp(self, file):
f = open(file, 'r')
if f.read(2) != 'BM':
f.close()
raise FormatError
f.seek(16, 1)
width = self.get_int(f.read(4)[::-1])
height = self.get_int(f.read(4)[::-1])
f.close()
return width, height, 'bmp'
def gif(self, file):
f = open(file, 'r')
if f.read(6) not in ('GIF89a', 'GIF87a'):
f.close()
raise FormatError
width = self.get_int(f.read(2)[::-1])
height = self.get_int(f.read(2)[::-1])
f.close()
return width, height, 'gif'
def size(n):
for x in ['bytes','KB','MB','GB','TB']:
if n < 1024.0:
return "%3.1f%s" % (n, x)
n /= 1024.0
def help():
print 'Use \'pyshack "first file" "second file" ...\''
class Progressbar:
if 'curses' in sys.modules.keys():
curses.setupterm()
bol = curses.tigetstr('cr')
up = curses.tigetstr('cuu1')
down = curses.tigetstr('cud1')
el = curses.tigetstr('el')
cyan = curses.tparm(curses.tigetstr('setf'), 3)
green = curses.tparm(curses.tigetstr('setf'), 2)
normal = curses.tigetstr('sgr0')
hide = curses.tigetstr('civis')
show = curses.tigetstr('cnorm')
verbose = 1
else: verbose = 0
imageshack = Imageshack()
fileno = sys.stdout.fileno()
def __init__(self, image, num, len):
messages = {'link' : self.link, 'state':self.state}
self.num = num+1
self.len = len
self.image = image
if self.verbose:
self.write('\n')
if not image.check():
if self.verbose:
self.writeCaption('')
self.write(self.green)
self.write(('Error: ' + image.error).center(52))
self.write(self.normal +self.bol + self.down)
else: self.write(self.image.file + ' ' + 'Error: ' + image.error + '\n')
else:
for message in self.imageshack.send(image):
if message[0] in messages:
messages[message[0]](*message[1:])
def writeCaption(self, s = ''):
caption = self.image.file.split('/')[-1]
caption += ' (%s x %s)' % (self.image.width, self.image.height)
caption += (' '+s) if s else ''
numlen = '[%s/%s]' % (self.num, self.len)
if (len(caption) + len(numlen) +1) < 52:
caption = caption.center(52)
cap = list(caption)
cap[len(cap) - len(numlen):] = list(' ' + numlen)
caption = ''.join(cap)
else:
caption += ' '+numlen
self.write(self.up)
self.write(self.bol + self.el)
self.write(self.cyan)
self.write(caption)
self.write(self.normal + self.down)
def writeState(self, state, len):
bar = '[%s]'%('=' * (state / 2) + ('>' if state / 2 < 50 else '=') + '-' * (50 -state / 2))
self.write(self.bol + self.el)
self.write(self.green)
self.write(bar)
self.write(self.normal)
self.write(' %s / %s' % (size(len), size(self.image.datalen)))
def write(self, s):
os.write(self.fileno, s)
def state(self, state, len):
if self.verbose:
if state !=100:
self.writeCaption('sending')
else:
self.writeCaption('receiving link')
self.writeState(state, len)
def link(self, link):
if self.verbose:
self.write(self.down)
self.write(link)
self.write(self.down)
else: self.write(self.image.file +' ' + link + '\n')
def main():
files = []
verbose = 1
if not sys.stdin.isatty():
for file in sys.stdin.read().split('\n'):
if file:
if file not in files:
files.append(file)
if [each for each in sys.argv[1:] if each in ['-h', '--help']]:
help()
return
if '-q' in sys.argv[1:]:
verbose = 0
sys.argv.remove('-q')
if '--quiet' in sys.argv[1:]:
verbose = 0
sys.argv.remove('--quiet')
for file in sys.argv[1:]:
if file:
if file not in files:
files.append(file)
if not sys.stdout.isatty():
verbose = 0
if Progressbar.verbose:
Progressbar.verbose = verbose
for file in files:
Progressbar(Image(file), files.index(file), len(files))
if __name__=='__main__':
main()