基于Python的Gmail销售统计程序:数值递增1时播放声音的实现
Hey there! Let's break down how to add those sound alerts when your submission or membership counts change by exactly +1 or -1. We'll cover two key parts: tracking the previous count values and playing the right sound at the right time.
1. How to Detect +1/-1 Changes
The trick here is to remember the last value of each counter every time we check the inbox. Then, when we get the new count, we calculate the difference between the new and old values:
- If
new_count - old_count == 1: That's an increment of 1—play your "positive" sound (like a cash register chime) - If
new_count - old_count == -1: That's a decrement of 1—play your "negative" sound - Any other difference (like bulk updates from your end-of-day cleanup) won't trigger a sound, which is exactly what you want.
2. Playing Sounds in Python
For cross-platform support, I recommend using the playsound library (it works on Windows, Mac, and Linux). First, install it via pip:
pip install playsound
If you're on Windows and don't want extra dependencies, you can use the built-in winsound module instead—just swap out the play_sound function with that (I'll note how in the code comments).
3. Modified Full Code
Here's your updated code with all the logic added. I've commented the key changes so you can follow along:
#! /usr/bin/python3 import imaplib import email import tkinter as tk from playsound import playsound # Install first: pip install playsound # For Windows-only, replace the line above with: # import winsound WIDTH = 1000 HEIGHT = 100 # Track the last known values for each counter (start at 0) last_submission_count = 0 last_membership_count = 0 def play_sound(sound_file): """Helper function to play sound files""" try: playsound(sound_file) # For Windows-only with winsound, use this instead: # winsound.PlaySound(sound_file, winsound.SND_FILENAME) except Exception as e: print(f"Oops, couldn't play sound: {e}") def update_submissions(): global last_submission_count # Tell Python we're using the global variable # Connect to Gmail (we could optimize this to connect once, but let's keep it simple first) mail = imaplib.IMAP4_SSL('imap.gmail.com', 993) mail.login('email@gmail.com', 'MyPassword') mail.select("Submissions") # Get unread messages typ, message_ids = mail.search(None, "UNSEEN") id_str = str(message_ids[0], encoding='utf8') # Calculate current count if id_str == '': current_count = 0 info1['text'] = 'no submissions' else: current_count = len(id_str.split(" ")) info1['text'] = f'{current_count} submission[s]' # Check for +1/-1 change and play sound count_diff = current_count - last_submission_count if count_diff == 1: play_sound("cash_register.wav") # Replace with your increment sound path elif count_diff == -1: play_sound("error_alert.wav") # Replace with your decrement sound path # Update the last count for next time last_submission_count = current_count # Schedule next update subs.after(1000, update_submissions) def update_memberships(): global last_membership_count mail = imaplib.IMAP4_SSL('imap.gmail.com', 993) mail.login('email@gmail.com', 'MyPassword') mail.select("Memberships") typ, message_ids = mail.search(None, "UNSEEN") id_str = str(message_ids[0], encoding='utf8') if id_str == '': current_count = 0 info2['text'] = 'no memberships' else: current_count = len(id_str.split(" ")) info2['text'] = f'{current_count} membership[s]' count_diff = current_count - last_membership_count if count_diff == 1: play_sound("cash_register.wav") elif count_diff == -1: play_sound("error_alert.wav") last_membership_count = current_count membs.after(1000, update_memberships) # Setup Tkinter windows (note: using two Tk() instances can cause issues—better to use Toplevel for one window!) membs = tk.Tk() subs = tk.Tk() membs.title('memberships counter') membs.configure(background="black") subs.title('submissions counter') subs.configure(background="black") # Position submissions window x = (subs.winfo_screenwidth()//5) - (WIDTH//5) y = (subs.winfo_screenheight()//5) - (HEIGHT//5) subs.geometry(f'{WIDTH}x{HEIGHT}+{x}+{y}') info1 = tk.Label(subs, text='nothing to display', bg="black", fg="green", font="Lucida_Console 40") info1.pack() # Position memberships window x = (membs.winfo_screenwidth()//2) - (WIDTH//2) y = (membs.winfo_screenheight()//2) - (HEIGHT//2) membs.geometry(f'{WIDTH}x{HEIGHT}+{x}+{y}') info2 = tk.Label(membs, text='nothing to display', bg="black", fg="red", font="Lucida_Console 40") info2.pack() # Start update loops update_submissions() update_memberships() # Run the Tkinter main loops membs.mainloop() subs.mainloop()
Quick Optimizations to Consider
- Reuse Gmail Connection: Right now, we log in to Gmail every second for each counter. That's unnecessary—you could create a single connection once and reuse it in both update functions to reduce overhead.
- Single Tk() Instance: Tkinter isn't designed to handle multiple
Tk()instances. Instead, make one window the mainTk()and the other aToplevel()child window—this will avoid weird behavior like unresponsive windows. - Error Handling: Add
try-exceptblocks around the Gmail login/select steps to handle network drops or login failures gracefully (so your program doesn't crash unexpectedly).
内容的提问来源于stack exchange,提问作者Smokeyparkin

