ShootNup: Upload su ImageShack dal tuo cellulare
Ho finalmente terminato la mia ultima applicazione: ShootNup. Come suggerisce già il titolo (shoot and upload), quest’applicazione permette di caricare le tue foto online su ImageShack, direttamente dal cellulare.
Tra le varie opzioni, è possibile selezionare come oggetto dell’upload una foto salvata in memoria oppure uno screenshot dello schermo del cellulare.
Una volta che l’immagine è stata inserita online, verrà restituito il link diretto ad essa che sarà conservato per tutta la sessione di lavoro.
L’applicazione fa uso della connessione ad internet, e dato il grande numero di dati che viene trasferito (a causa del peso delle immagini) si consiglia l’utilizzo di una connessione wi-fi o di un abbonamento ad internet.
Questo programma è scritto in Python e richiede ovviamente che l’interprete del linguaggio sia installato sul vostro cellulare. Oltre a ciò utilizza due moduli esterni, che sono appswitch e dialog: il primo serve a passare l’applicazione dalla modalità background a foreground quando si salva uno screenshot, il secondo serve per mostrare le schermate di stato (caricamento in corso, upload in corso, ecc.). Non essendo strettamente necessari per l’upload, potete anche non installarli, ma li ho inclusi nel file .zip che segue e consiglio caldamente di installarli.
Ecco qualche screenshot (click per ingrandire):
- Funzione screenshot
- Finestra principale
- Funzioni di upload
- Url salvati
- Url diretto
- Language English
Download link:
-Download ShootNup.zip (dialog.sis, appswitch.sis, ShootNup.sis)-
Segue il codice sorgente dell’applicazione.
import os
import e32
import urllib
import e32dbm
import httplib
import appuifw
import graphics
import globalui
from time import time, altzone
# These modules are not essential, but program looks better with them.
try:
import dialog
except ImportError:
dialog = None
try:
import appswitch
except ImportError:
appswitch = None
# Var
COL = (250, 0, 0) # File select color
FILE = None # File to upload
SYS_DIR = ur'C:\Data\ShootNup' # System dir
if not os.path.isdir(SYS_DIR): os.mkdir(SYS_DIR)
URL_FILE = os.path.join(SYS_DIR, u'url_list.txt') # Default URL file
CFG_FILE = os.path.join(SYS_DIR, u'config') # Config file
cfg = e32dbm.open(CFG_FILE, 'c')
FONT1 = ('normal', 20) # Font
FONT2 = ('normal', 14) # Small font
preview = None # Uploading image preview
PREVIEW = ur'%s\preview.jpg' % SYS_DIR # Uploading file preview
NW = 130 # Preview image width
NH = 100 # Preview image height
url_list = [] # Url list
SYS_TIME = time() # App start timestamp
def draw(r=None):
"""Draws background"""
global preview
c.clear((255, 255, 0))
c.text((4, 20), text['author'], font=FONT1)
c.text((4, 45), text['site'], font=FONT1)
c.text((4, 70), text['description_1'], font=FONT2)
c.text((4, 88), text['description_2'], font=FONT2)
if FILE:
path = FILE.split('\\')
path = [p.decode('utf-8') for p in path] # I need an unicode path
if len(path) > 3:
file_name = u'%s\\%s\\...\\%s' % (path[0], path[1], path[-1])
else:
file_name = FILE.decode('utf-8')
else:
file_name = text['no_file']
c.text((4, 110), u'File = %s' % file_name, font=FONT2, fill = COL)
# Try to show FILE preview
try:
last_m = os.path.getmtime(PREVIEW)
if last_m > SYS_TIME + altzone:
preview = graphics.Image.open(PREVIEW)
c.blit(preview, target=(4, 120))
except SymbianError:
pass
def photo():
"""Starts camera"""
from camera import start_finder
from key_codes import EKeySelect
appuifw.note(text['ok_to_shoot'], 'info')
start_finder(lambda img: c.blit(img))
c.bind(EKeySelect, shoot)
def shoot():
"""Shoot a photo"""
from camera import stop_finder, take_photo, image_sizes, release
global FILE
if dialog:
d = dialog.Wait(text['taking_photo'], False)
d.show()
stop_finder()
FILE = '%s\\photo.jpg' % SYS_DIR.encode('utf-8')
# Shoot the photo
img = take_photo(size=image_sizes()[0],
mode='RGB',
flash='auto')
img.save(FILE)
try:
preview = graphics.Image.open(FILE.decode('utf-8'))
w, h = preview.size
if w > h: preview.resize((NW, NW*h/w)).save(PREVIEW)
else: preview.resize((NH*w/h, NH)).save(PREVIEW)
except SymbianError:
appuifw.error(text['preview_error'], 'error')
if dialog:
d.close()
appuifw.note(text['photo_taken'], 'conf')
release()
def select_last():
"""Select last shot in E:\images\ """
global FILE
from time import strftime
try:
images_dir = os.listdir(r'E:\images\%s' % strftime('%Y%m'))
photos = os.listdir(r'E:\images\%s\%s' % (strftime('%Y%m'), images_dir[-1]))
if globalui.global_query(u'%s %s?' % (text['select_last'], photos[-1].decode('utf-8'))):
FILE = r'E:\images\%s\%s\%s' % (strftime('%Y%m'), images_dir[-1], photos[-1])
if globalui.global_query(text['preview_query']):
if dialog:
d = dialog.Wait(text['preview'], False)
d.show()
e32.ao_sleep(1)
try:
preview = graphics.Image.open(FILE.decode('utf-8'))
w, h = preview.size
if w > h: preview.resize((NW, NW*h/w)).save(PREVIEW)
else: preview.resize((NH*w/h, NH)).save(PREVIEW)
except SymbianError:
appuifw.error(text['preview_error'], 'error')
if dialog:
d.close()
else:
# Try to del previous preview file
try:
os.unlink(PREVIEW)
except OSError:
pass
except OSError:
appuifw.note(text['last_not_found'], 'error')
def screenshot():
"""Starts the screenshot capturer"""
import keycapture
global capturer, screen_lock
capturer = keycapture.KeyCapturer(screenshot_key)
capturer.keys = ([35]) # Hash code
capturer.start()
appuifw.note(text['screenshot_info'], 'info')
if appswitch:
appswitch.switch_to_bg(u'Python')
appswitch.switch_to_bg(u'ShootNup')
screen_lock = e32.Ao_lock()
screen_lock.wait()
def screenshot_key(event):
"""Capture the screenshot"""
from graphics import screenshot
global FILE
ss = screenshot()
ss.save(ur'%s\screenshot.jpg' % SYS_DIR)
FILE = r'%s\screenshot.jpg' % SYS_DIR.encode('utf-8')
try:
preview = graphics.Image.open(FILE.decode('utf-8'))
w, h = preview.size
if w > h: preview.resize((NW, NW*h/w)).save(PREVIEW)
else: preview.resize((NH*w/h, NH)).save(PREVIEW)
except SymbianError:
appuifw.error(text['preview_error'], 'error')
if appswitch:
appswitch.switch_to_fg(u'Python')
appswitch.switch_to_fg(u'ShootNup')
globalui.global_note(text['screenshot_taken'])
capturer.stop()
screen_lock.signal()
def list(path):
"""List a directory and return the selected file"""
# Previous directory
if path and path.endswith(r'\..'):
# Show memories
if path in [r'C:\\..', r'E:\\..', r'C:\..', r'E:\..']:
files = ['C:', 'E:']
path = ''
# Show previous directory
else:
path = os.path.split(os.path.split(path)[0])[0]
# List the dir
files = os.listdir(path)
files.sort()
files[0:0] = [r'..']
# List the dir
elif path:
files = os.listdir(path)
files.sort()
files[0:0] = [r'..']
ufiles = [i.decode('utf-8') for i in files] # appuifw require unicode
try:
selected = files[appuifw.selection_list(ufiles, 1)]
except TypeError:
# No file selected
return None
# If you select E: it mustn't return \E:!
if path:
return '\\'.join([path, selected])
else:
return selected
def mimetype_ext(filename):
"""Choose a mimetype according to the file extension"""
supported_mimetypes = {
'.jpe': 'image/pjpeg',
'.jpeg': 'image/jpeg',
'.jpg': 'image/jpeg',
'.png': 'image/png',
'.tif': 'image/tiff',
'.tiff': 'image/tiff',
'.bmp': 'image/bmp',
'.gif': 'image/gif',
'.ico': 'image/x-icon',
'.pic': 'image/pict',
'.pict': 'image/pict',
'.svf': 'image/x-dwg'
}
ext = os.path.splitext(filename)[1]
if ext in supported_mimetypes:
return supported_mimetypes[ext]
else:
appuifw.note(text['not_supported'], 'error')
return 'application/octet-stream'
def select_file():
"""Select a file to upload"""
global FILE
appuifw.note(text['select_file'])
FILE = None # File not selected
path = r'C:\\..' # Default dir (back to memories)
temp = list(path)
while not FILE:
if temp and os.path.isfile(temp):
FILE = temp
if globalui.global_query(text['preview_query']):
if dialog:
d = dialog.Wait(text['preview'], False)
d.show()
e32.ao_sleep(1)
try:
preview = graphics.Image.open(FILE.decode('utf-8'))
w, h = preview.size
if w > h: preview.resize((NW, NW*h/w)).save(PREVIEW)
else: preview.resize((NH*w/h, NH)).save(PREVIEW)
except SymbianError:
appuifw.error(text['preview_error'], 'error')
if dialog:
d.close()
else:
# Try to del previous preview file
try:
os.unlink(PREVIEW)
except OSError:
pass
appuifw.note(text['file_selected'], 'conf')
elif temp and os.path.isdir(temp):
temp = list(temp)
else:
return None
def upload():
# Check you select a file to upload
try:
image = open(FILE).read()
except IOError:
appuifw.note(text['no_file'], 'error')
return None
# Sending parameters
params = [('MAX_FILE_SIZE', '3145728'),
('refer', 'http://reg.imageshack.us/v_images.php')]
files = [('fileupload', FILE, image)]
url = post_multipart('imageshack.us', 80, '/index.php', params, files)
if url:
url_list.append(url.decode('utf-8'))
appuifw.query(text['direct_url'], 'text', url.decode('utf-8'))
def post_multipart(host, port, selector, fields, files):
"""
Post fields and files to an http host as multipart/form-data.
fields is a sequence of (name, value) elements for regular form fields.
files is a sequence of (name, filename, value)
elements for data to be uploaded as files
Return the server's response page.
"""
content_type, body = encode_multipart_formdata(fields, files)
h = httplib.HTTP(host, port)
h.putrequest('POST', selector)
h.putheader('content-type', content_type)
h.putheader('content-length', str(len(body)))
if dialog:
d = dialog.Wait(text['uploading'], False)
try:
if dialog:
d.show()
h.endheaders()
h.send(body)
code, errmsg, headers = h.getreply()
except Exception, errore:
if dialog:
d.close()
appuifw.note(text['conn_error'], 'error')
appuifw.note(str(errore).decode('utf-8'), 'error')
return None
if dialog:
d.close()
# If success, return direct url
if code == 302:
return headers.dict['location'].replace('content.php?page=done&l=', '')
else:
appuifw.note(u'%s %d!' % (text['error'], code), 'error')
return None
def encode_multipart_formdata(fields, files):
"""
fields is a sequence of (name, value) elements for regular form
fields.
files is a sequence of (name, filename, value) elements for data to
be uploaded as files
Return (content_type, body) ready for httplib.HTTP instance
"""
BOUNDARY = '---------------------------13049614110900'
L = []
for (key, value) in fields:
L.extend(['--' + BOUNDARY,
'Content-Disposition: form-data; name="%s"' % key,
'',
value])
for (key, filename, value) in files:
L.extend(['--' + BOUNDARY,
'Content-Disposition: form-data; name="%s"; filename="%s"' % (key, filename),
'Content-type: %s' % mimetype_ext(FILE),
'',
value])
L.append('--' + BOUNDARY + '--')
L.append('')
body = '\r\n'.join(L)
content_type = 'multipart/form-data; boundary=%s' % BOUNDARY
return content_type, body
def show_url(item=None):
"""Show url list"""
if not url_list:
appuifw.note(text['no_url'], 'error')
return
if item:
appuifw.query(text['direct_url'], 'text', item)
else:
names_list = [url.split('/')[-1] for url in url_list]
select = appuifw.selection_list(names_list)
try:
show_url(url_list[select])
except TypeError:
# No link selected
pass
def save_url():
"""Save url list"""
file_name = appuifw.query(text['path'], 'text', URL_FILE)
if not url_list:
appuifw.note(text['no_url'], 'error')
return
try:
f = open(file_name, 'a')
except IOError:
appuifw.note(text['name_error'], 'error')
return
for u in url_list:
f.write(u+'\n')
f.close()
appuifw.note(u'%s %s' % (text['url_saved'], SYS_DIR), 'conf')
def quit():
"""Ask for saving url, then quit"""
if url_list and appuifw.query(text['save_before_exit'], 'query'):
save_url()
try:
os.unlink(PREVIEW)
except OSError:
pass
lock.signal()
appuifw.app.set_exit()
def lang(l='en'):
"""Choose application language"""
global text
if l == 'it':
cfg[u'lang'] = 'it'
text = {
'author': u'Created by Ale152',
'site': u'www.Wirgilio.it',
'description_1': u'Scatta una foto o seleziona un file,',
'description_2': u'poi clicca su Upload.',
'no_file': u'Nessuno',
'ok_to_shoot': u'Premere OK per scattare',
'taking_photo': u'Acquisizione foto in corso...',
'photo_taken': u'Foto acquisita.',
'preview_query': u'Creare anteprima immagine?',
'preview_error': u'Impossibile creare anteprima!',
'preview': u'Creazione anteprima in corso...',
'last_not_found': u'Foto non trovata!',
'screenshot_info': u'Premere # per salvare screenshot',
'screenshot_taken': u'Screenshot catturato!',
'not_supported': 'File non supportato!',
'select_file': u'Selezionare un file da uppare.',
'file_selected': u'File selezionato.',
'no_file': u'Nessun file selezionato!',
'select_last': u'Selezionare',
'direct_url': u'Url diretto',
'uploading': u'Upload in corso...',
'conn_error': u'Errore di connessione!',
'error': u'Errore',
'no_url': u'Nessun URL salvato!',
'path': u'Indirizzo',
'name_error': u'Nome file non valido!',
'url_saved': u'URL salvati in',
'save_before_exit': u'Salvare lista URL acquisiti?',
# Menu
'select': u'Seleziona',
'file': u'File',
'shoot': u'Scatta foto',
'last': u'Ultima foto scattata',
'screenshot': u'Screenshot',
'URL': u'URL',
'show_url': u'Mostra URL',
'save_url': u'Salva lista',
'language': u'Lingua',
'italian': u'Italiano',
'english': u'Inglese',
'upload': u'Upload!',
'quit': u'Esci'
}
elif l == 'en':
cfg[u'lang'] = 'en'
text = {
'author': u'Created by Ale152',
'site': u'www.Wirgilio.it',
'description_1': u'Shoot a photo or select a file, then',
'description_2': u'click on Upload!',
'no_file': u'No file',
'ok_to_shoot': u'Press OK to shoot',
'taking_photo': u'Taking photo...',
'photo_taken': u'Photo taken!',
'preview_query': u'Create an image preview?',
'preview_error': u'Unable to create preview!',
'preview': u'Creating image preview...',
'last_not_found': u'Photo not found!',
'screenshot_info': u'Press # to save screenshot',
'screenshot_taken': u'Screenshot taken!',
'not_supported': 'File not supported!',
'select_file': u'Select a file to upload.',
'file_selected': u'File selected.',
'no_file': u'No file selected!',
'select_last': u'Select',
'direct_url': u'Direct URL',
'uploading': u'Upload...',
'conn_error': u'Connection error!',
'error': u'Error',
'no_url': u'No URL Saved!',
'path': u'File path',
'name_error': u'Filename not valid!',
'url_saved': u'URL saved in',
'save_before_exit': u'Save URL acquired before exit?',
# Menu
'select': u'Select',
'file': u'File',
'shoot': u'Take foto',
'last': u'Last taken photo',
'screenshot': u'Screenshot',
'URL': u'URL',
'show_url': u'Show URL',
'save_url': u'Save URL list',
'language': u'Language',
'italian': u'Italian',
'english': u'English',
'upload': u'Upload!',
'quit': u'Quit'
}
# Upgrade menu
appuifw.app.menu = [
(text['select'], (
(text['file'], select_file),
(text['shoot'], photo),
(text['last'], select_last),
(text['screenshot'], screenshot))),
(text['URL'], (
(text['show_url'], show_url),
(text['save_url'], save_url))),
(text['language'], (
(text['italian'], lambda: lang('it')),
(text['english'], lambda: lang('en')))),
(text['upload'], upload),
(text['quit'], quit)
]
# Check for language in config file
if u'lang' in cfg:
lang(cfg[u'lang'])
else:
lang()
# Application body
c = appuifw.Canvas(redraw_callback=draw)
appuifw.app.body = c
appuifw.app.title = u'ShootNup'
appuifw.app.exit_key_handler = quit
# Prevent app closing
lock = e32.Ao_lock()
lock.wait()






