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):
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()