class GUI: def __init__(self): self.window = Tk() self.main_window_init() self.client = Snapchat() self.start() def start(self): self.window.mainloop() def main_window_init(self): # set window title self.window.wm_title('pySnap') # configure menu menu_bar = Menu(self.window) self.window.config(menu=menu_bar) # File menu file_menu = Menu(menu_bar, tearoff=0) file_menu.add_command(label='Send media', command=self.send_media) file_menu.add_separator() file_menu.add_command(label='Exit', command=self.window.quit) menu_bar.add_cascade(label='File', menu=file_menu) # Edit menu account_menu = Menu(menu_bar, tearoff=0) account_menu.add_command( label='Copy Token', command=lambda: [ pyperclip.copy(self.client.auth_token), tkMessageBox.showinfo('Token copied', 'Auth token copied to clipboard!') ]) account_menu.add_command(label='Logout') account_menu.add_command(label='Switch user') menu_bar.add_cascade(label='Accounts', menu=account_menu) # Prepare the image canvas to be replaced by map image self.snap_list = Frame(self.window, width=800, height=600) self.snap_list.pack(fill=BOTH, expand=1, side=RIGHT) self.window.withdraw() w = Toplevel(self.window) msg = Label(w, text='Login') msg.pack() username_panel = PanedWindow(w) username_panel.pack(fill=BOTH, expand=1) password_panel = PanedWindow(w) password_panel.pack(fill=BOTH, expand=1) token_panel = PanedWindow(w) token_panel.pack(fill=BOTH, expand=1) Label(username_panel, text='Username').pack(side=LEFT) username_entry = Entry(username_panel) username_entry.pack(side=RIGHT) Label(password_panel, text='Password').pack(side=LEFT) password_entry = Entry(password_panel, show='*') password_entry.pack(side=RIGHT) Label(token_panel, text='Auth Token').pack(side=LEFT) token_entry = Entry(token_panel) token_entry.pack(side=RIGHT) panel = PanedWindow(w) panel.pack() ok_btn = Button(panel, text=' OK ', command=lambda: self.login(w, username_entry.get( ), password_entry.get(), token_entry.get())) ok_btn.pack(side=LEFT) cancel_btn = Button(panel, text=' Cancel ', command=lambda: self.cancel_login(w)) cancel_btn.pack(side=RIGHT) def login(self, w, username, password, auth_token): w.destroy() if password == '': if not self.client.login_token(username, auth_token): tkMessageBox.showinfo('Failed to login', 'Wrong username or password?') self.window.quit() return else: if not self.client.login(username, password): tkMessageBox.showinfo('Failed to login', 'Wrong username or password?') self.window.quit() return snaps = self.client.get_snaps() if not snaps: tkMessageBox.showinfo('Unknown error', 'Something went wrong.') self.window.quit() return Label(self.snap_list, text='Logged in as {0}\n'.format(username)).pack() for snap in snaps: snap_panel = PanedWindow(self.snap_list) snap_panel.pack(fill=X, expand=1) Label(snap_panel, text='{0} ({1}s, sent {2})'.format( snap['sender'], snap['time'], datetime.fromtimestamp(snap['sent'] / 1000))).pack(side=LEFT) open_btn = Button(snap_panel, text=' Open ', command=lambda snap=snap: self.open_snap(snap)) open_btn.pack(side=RIGHT) self.window.update() self.window.deiconify() def cancel_login(self, w): w.destroy() self.window.quit() @staticmethod def route_map_callback(filename, data): route_map = PhotoImage(file=filename) data.configure(image=route_map) data.image = route_map def send_media(self): options = dict(defaultextension='.jpg', filetypes=[('Image file', '.jpg'), ('Video file', '.mp4')], parent=self.window, title='Open media file') infile = tkFileDialog.askopenfilename(**options) # TODO: add checking for filesizes above 1MB if infile: self.select_recipients(infile) def select_recipients(self, path): w = Toplevel(self.window) msg = Label(w, text='Select recipients') msg.pack() recipient_list = Listbox(w, selectmode=MULTIPLE) recipients = self.client.friends for name in recipients: recipient_list.insert(END, name) recipient_list.pack(fill=BOTH, expand=1) timer_panel = PanedWindow(w) timer_panel.pack(fill=BOTH, expand=1) Label(timer_panel, text='Send delay (s):').pack(side=LEFT) timer_spinbox = Spinbox(timer_panel, from_=0, to=3600, width=6, repeatdelay=200, repeatinterval=5) timer_spinbox.pack(side=RIGHT) panel = PanedWindow(w) panel.pack() ok_btn = Button(panel, text=' OK ', command=lambda: self.send_to_recipients( w, recipients, recipient_list.curselection(), path, timer_spinbox.get())) ok_btn.pack(side=LEFT) cancel_btn = Button(panel, text=' Cancel ', command=w.destroy) cancel_btn.pack(side=RIGHT) def send_to_recipients(self, w, friends, selected, path, timer_time): w.destroy() recipient_list = [] for f in selected: recipient_list.append(friends[f]) if timer_time == 0: self.send_helper(path, recipient_list) else: self.window.after( int(timer_time) * 1000, lambda: self.send_helper(path, recipient_list)) def send_helper(self, path, recipient_list): if self.client.send_snap(path, recipient_list): tkMessageBox.showinfo( 'Send successful', 'Sent {0} to {1} recipient(s)'.format(path, len(recipient_list))) else: tkMessageBox.showinfo("Failed to send", "An error occurred") def open_snap(self, snap): dt = datetime.fromtimestamp(snap['sent'] / 1000) ext = self.client.media_type(snap['media_type'], binary=False) timestamp = str(snap['sent']).replace(':', '-') filename = '{}+{}+{}.{}'.format(timestamp, snap['sender'], snap['id'], ext) path = PATH + filename if not os.path.isfile(path): data = self.client.get_snap(snap['id']) with open(path, 'wb') as outfile: outfile.write(data) snap['path'] = path file_path = snap['path'] # open /dev/null or equivalent so we can redirect stdout/stderr to it nullfile = open(os.devnull, 'w') scheduler = sched.scheduler(time.time, time.sleep) if sys.platform.startswith('linux'): p = subprocess.Popen(['xdg-open', file_path], stdout=nullfile, stderr=nullfile, preexec_fn=os.setsid) elif sys.platform.startswith('darwin'): p = subprocess.Popen(['open', file_path], stdout=nullfile, stderr=nullfile) elif sys.platform.startswith('win'): p = subprocess.Popen(['start /WAIT', file_path], stdout=nullfile, stderr=nullfile) else: print 'I don\'t recognize your operating system: {0}'.format( sys.platform) self.window.after(snap['time'] * 1000 + 1000, lambda: self.mark_read(snap, p)) ''' scheduler.enter(snap['time'], 1, self.mark_read, (snap, p)) t = threading.Thread(target=lambda: scheduler.run) t.start() ''' def mark_read(self, snap, p): print 'marking read' # self.client.mark_read(snap) os.remove(snap['path']) if sys.platform.startswith('linux'): os.killpg(p.pid, signal.SIGTERM) elif sys.platform.startswith('win'): p.kill()
class GUI: def __init__(self): self.window = Tk() self.main_window_init() self.client = Snapchat() self.start() def start(self): self.window.mainloop() def main_window_init(self): # set window title self.window.wm_title('pySnap') # configure menu menu_bar = Menu(self.window) self.window.config(menu=menu_bar) # File menu file_menu = Menu(menu_bar, tearoff=0) file_menu.add_command(label='Send media', command=self.send_media) file_menu.add_separator() file_menu.add_command(label='Exit', command=self.window.quit) menu_bar.add_cascade(label='File', menu=file_menu) # Edit menu account_menu = Menu(menu_bar, tearoff=0) account_menu.add_command(label='Copy Token', command= lambda: [pyperclip.copy(self.client.auth_token), tkMessageBox.showinfo('Token copied', 'Auth token copied to clipboard!')]) account_menu.add_command(label='Logout') account_menu.add_command(label='Switch user') menu_bar.add_cascade(label='Accounts', menu=account_menu) # Prepare the image canvas to be replaced by map image self.snap_list = Frame(self.window, width=800, height=600) self.snap_list.pack(fill=BOTH, expand=1, side=RIGHT) self.window.withdraw() w = Toplevel(self.window) msg = Label(w, text='Login') msg.pack() username_panel = PanedWindow(w) username_panel.pack(fill=BOTH, expand=1) password_panel = PanedWindow(w) password_panel.pack(fill=BOTH, expand=1) token_panel = PanedWindow(w) token_panel.pack(fill=BOTH, expand=1) Label(username_panel, text='Username').pack(side=LEFT) username_entry = Entry(username_panel) username_entry.pack(side=RIGHT) Label(password_panel, text='Password').pack(side=LEFT) password_entry= Entry(password_panel, show='*') password_entry.pack(side=RIGHT) Label(token_panel, text='Auth Token').pack(side=LEFT) token_entry = Entry(token_panel) token_entry.pack(side=RIGHT) panel = PanedWindow(w) panel.pack() ok_btn = Button(panel, text=' OK ', command=lambda: self.login(w, username_entry.get(), password_entry.get(), token_entry.get())) ok_btn.pack(side=LEFT) cancel_btn = Button(panel, text=' Cancel ', command=lambda: self.cancel_login(w)) cancel_btn.pack(side=RIGHT) def login(self, w, username, password, auth_token): w.destroy() if password == '': if not self.client.login_token(username, auth_token): tkMessageBox.showinfo('Failed to login', 'Wrong username or password?') self.window.quit() return else: if not self.client.login(username, password): tkMessageBox.showinfo('Failed to login', 'Wrong username or password?') self.window.quit() return snaps = self.client.get_snaps() if not snaps: tkMessageBox.showinfo('Unknown error', 'Something went wrong.') self.window.quit() return Label(self.snap_list, text='Logged in as {0}\n'.format(username)).pack() for snap in snaps: snap_panel = PanedWindow(self.snap_list) snap_panel.pack(fill=X, expand=1) Label(snap_panel, text='{0} ({1}s, sent {2})'.format(snap['sender'], snap['time'], datetime.fromtimestamp(snap['sent']/1000))).pack(side=LEFT) open_btn = Button(snap_panel, text=' Open ', command=lambda snap=snap: self.open_snap(snap)) open_btn.pack(side=RIGHT) self.window.update() self.window.deiconify() def cancel_login(self, w): w.destroy() self.window.quit() @staticmethod def route_map_callback(filename, data): route_map = PhotoImage(file=filename) data.configure(image=route_map) data.image = route_map def send_media(self): options = dict(defaultextension='.jpg', filetypes=[('Image file', '.jpg'), ('Video file', '.mp4')], parent=self.window, title='Open media file') infile = tkFileDialog.askopenfilename(**options) # TODO: add checking for filesizes above 1MB if infile: self.select_recipients(infile) def select_recipients(self, path): w = Toplevel(self.window) msg = Label(w, text='Select recipients') msg.pack() recipient_list = Listbox(w, selectmode=MULTIPLE) recipients = self.client.friends for name in recipients: recipient_list.insert(END, name) recipient_list.pack(fill=BOTH, expand=1) timer_panel = PanedWindow(w) timer_panel.pack(fill=BOTH, expand=1) Label(timer_panel, text='Send delay (s):').pack(side=LEFT) timer_spinbox = Spinbox(timer_panel, from_=0, to=3600, width=6, repeatdelay=200, repeatinterval=5) timer_spinbox.pack(side=RIGHT) panel = PanedWindow(w) panel.pack() ok_btn = Button(panel, text=' OK ', command=lambda: self.send_to_recipients(w, recipients, recipient_list.curselection(), path, timer_spinbox.get())) ok_btn.pack(side=LEFT) cancel_btn = Button(panel, text=' Cancel ', command=w.destroy) cancel_btn.pack(side=RIGHT) def send_to_recipients(self, w, friends, selected, path, timer_time): w.destroy() recipient_list = [] for f in selected: recipient_list.append(friends[f]) if timer_time == 0: self.send_helper(path, recipient_list) else: self.window.after(int(timer_time) * 1000, lambda: self.send_helper(path, recipient_list)) def send_helper(self, path, recipient_list): if self.client.send_snap(path, recipient_list): tkMessageBox.showinfo('Send successful', 'Sent {0} to {1} recipient(s)'.format(path, len(recipient_list))) else: tkMessageBox.showinfo("Failed to send", "An error occurred") def open_snap(self, snap): dt = datetime.fromtimestamp(snap['sent'] / 1000) ext = self.client.media_type(snap['media_type'], binary=False) timestamp = str(snap['sent']).replace(':', '-') filename = '{}+{}+{}.{}'.format(timestamp, snap['sender'], snap['id'], ext) path = PATH + filename if not os.path.isfile(path): data = self.client.get_snap(snap['id']) with open(path, 'wb') as outfile: outfile.write(data) snap['path'] = path file_path = snap['path'] # open /dev/null or equivalent so we can redirect stdout/stderr to it nullfile = open(os.devnull, 'w') scheduler = sched.scheduler(time.time, time.sleep) if sys.platform.startswith('linux'): p = subprocess.Popen(['xdg-open', file_path], stdout=nullfile, stderr=nullfile, preexec_fn=os.setsid) elif sys.platform.startswith('darwin'): p = subprocess.Popen(['open', file_path], stdout=nullfile, stderr=nullfile) elif sys.platform.startswith('win'): p = subprocess.Popen(['start /WAIT', file_path], stdout=nullfile, stderr=nullfile) else: print 'I don\'t recognize your operating system: {0}'.format(sys.platform) self.window.after(snap['time'] * 1000 + 1000, lambda: self.mark_read(snap, p)) ''' scheduler.enter(snap['time'], 1, self.mark_read, (snap, p)) t = threading.Thread(target=lambda: scheduler.run) t.start() ''' def mark_read(self, snap, p): print 'marking read' # self.client.mark_read(snap) os.remove(snap['path']) if sys.platform.startswith('linux'): os.killpg(p.pid, signal.SIGTERM) elif sys.platform.startswith('win'): p.kill()
from snapchat import Snapchat import getpass PATH = './snaps/' EXTENSIONS = ['jpeg', 'jpg', 'mp4'] USERNAME = None PASSWORD = None s = Snapchat() if USERNAME is None: USERNAME = raw_input('username: '******'password: '******'sc.png', '') snaps = s.get_snaps() for snap in snaps: data = s.get_snap(snap['id']) if data: ext = s.media_type(data) timestamp = str(snap['sent']).replace(':', '-') filename = '{}+{}+{}.{}'.format(timestamp, snap['sender'], snap['id'], ext) path = PATH + filename with open(path, 'wb') as outfile: outfile.write(data)
def cli(): clear() s = Snapchat() username = raw_input('Please enter username: '******'win'): password = getpass.getpass('Please enter password: '******'Please enter password (empty for token entry): ') if password == '': auth_token = raw_input('Please enter auth token: ') if not s.login_token(username, auth_token): raw_input('Invalid username/auth token combo') clear() exit() else: if not s.login(username, password): raw_input('Invalid username/password combo') clear() exit() pynotify.init("pySnap") queue = Queue.Queue() bg_scheduler = sched.scheduler(time.time, time.sleep) bg_scheduler.enter(300, 1, check_snaps, (s, bg_scheduler, queue)) bg_check = threading.Thread(target=bg_scheduler.run) bg_check.setDaemon(True) bg_check.start() snaps = s.get_snaps() user_input = None functions = { 'R': lambda: s.get_snaps(), 'S': send } clear() while user_input != 'X': print 'Welcome to Snapchat!' print 'Logged in as {0} (token {1})'.format(username, s.auth_token) print print '{0} pending snaps:'.format(len(snaps)) num = 1 for snap in snaps: #print snap #print snap['media_type'] dt = datetime.fromtimestamp(snap['sent'] / 1000) ext = s.media_type(snap['media_type'], binary=False) timestamp = str(snap['sent']).replace(':', '-') filename = '{}+{}+{}.{}'.format(timestamp, snap['sender'], snap['id'], ext) path = PATH + filename # check if file already exists so we don't need to redownload ''' if not os.path.isfile(path): data = s.get_snap(snap['id']) with open(path, 'wb') as outfile: outfile.write(data) ''' snap['path'] = path print '[{0}] Snap from {1} ({2}s, Sent {3})'.format(num, snap['sender'], snap['time'], dt) num += 1 print print '[R] - refresh snaps' print '[S] - send a snap' print '[X] - exit' user_input = raw_input('Enter an option: ').upper() num_input = int(user_input) if user_input.isdigit() else None if len(snaps) >= num_input > 0: dt = datetime.fromtimestamp(snap['sent'] / 1000) ext = s.media_type(snap['media_type'], binary=False) timestamp = str(snap['sent']).replace(':', '-') filename = '{}+{}+{}.{}'.format(timestamp, snap['sender'], snap['id'], ext) path = PATH + filename snap = snaps[num_input - 1] if not os.path.isfile(path): data = s.get_snap(snap['id']) with open(path, 'wb') as outfile: outfile.write(data) snap['path'] = path file_path = snap['path'] # open /dev/null or equivalent so we can redirect stdout/stderr to it nullfile = open(os.devnull, 'w') # cross-platform method to open a media file p = None scheduler = sched.scheduler(time.time, time.sleep) # try: if True: if sys.platform.startswith('linux'): p = subprocess.Popen(['xdg-open', file_path], stdout=nullfile, stderr=nullfile, preexec_fn=os.setsid) elif sys.platform.startswith('darwin'): p = subprocess.Popen(['open', file_path], stdout=nullfile, stderr=nullfile) elif sys.platform.startswith('win'): p = subprocess.Popen(['start /WAIT', file_path], stdout=nullfile, stderr=nullfile) else: print 'I don\'t recognize your operating system: {0}'.format(sys.platform) scheduler.enter(snap['time'], 1, mark_read, (s, snap, p, queue)) t = threading.Thread(target=scheduler.run) t.start() # except: # print 'Uh oh, I was unable to open the file.' elif user_input in functions: if user_input == 'R': queue.put(functions[user_input]()) print 'Refreshed!' else: functions[user_input](s) elif user_input != 'X': print 'I don\'t recognize that command.' if user_input != 'X': raw_input('Press enter to continue...') clear() if not queue.empty(): while not queue.empty(): buf = queue.get() new_snaps = [] for st in buf: found = False for snap in snaps: if st['id'] == snap['id']: found = True break if found == True: new_snaps.append(st) for snap in new_snaps: title = 'New snap from {0}!'.format(snap['sender']) dt = datetime.fromtimestamp(snap['sent'] / 1000) message = '{0} seconds, sent {1}'.format(snap['time'], dt) notice = pynotify.Notification(title, message) notice.show() # snaps = buf sys.exit(0)