ShootNup: Upload su ImageShack dal tuo cellulare

Finestra principale

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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
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()