├── .gitignore ├── pomodoro-timer ├── .gitignore ├── README.md └── pomodoro_timer.py ├── expense-tracker ├── .gitignore ├── README.md └── expense_tracker.py ├── password-manager ├── .gitignore ├── README.md └── password_manager.py ├── file-organizer ├── .gitignore ├── README.md └── file_organizer.py ├── youtube-video-manager ├── youtube.txt └── youtube_manager.py ├── currency-converter ├── .gitignore ├── README.md └── currency_converter.py ├── qr-code-generator ├── qr_code_generator.py └── README.md ├── mini-games ├── ceasor_cypher.py └── black_jack.py ├── requirements.txt ├── time-greeting └── time_greeting.py ├── text-editor ├── README.md └── text_editor.py ├── rock-paper-scissors ├── rock-paper-scissor2.py ├── README.md └── rock_paper_scissors.py ├── music-player ├── README.md └── music_player.py ├── chatbot ├── README.md └── chatbot.py ├── weather-detection ├── README.md └── weather_detection.py ├── language-translator └── translator.py ├── morse-code-translator └── morse_translator.py ├── typing-speed-test └── typing_speed_test.py ├── internet-speed-test └── internet_speed_test.py ├── README.md └── tic-tac-toe └── tic_tac_toe.py /.gitignore: -------------------------------------------------------------------------------- 1 | .env -------------------------------------------------------------------------------- /pomodoro-timer/.gitignore: -------------------------------------------------------------------------------- 1 | pomodoro_stats.json 2 | *.pyc 3 | __pycache__/ 4 | -------------------------------------------------------------------------------- /expense-tracker/.gitignore: -------------------------------------------------------------------------------- 1 | expenses.json 2 | expenses_export_*.csv 3 | *.pyc 4 | __pycache__/ 5 | -------------------------------------------------------------------------------- /password-manager/.gitignore: -------------------------------------------------------------------------------- 1 | passwords.json 2 | key.key 3 | master.hash 4 | *.pyc 5 | __pycache__/ 6 | -------------------------------------------------------------------------------- /file-organizer/.gitignore: -------------------------------------------------------------------------------- 1 | organization_history.json 2 | file_organizer.log 3 | *.pyc 4 | __pycache__/ 5 | -------------------------------------------------------------------------------- /youtube-video-manager/youtube.txt: -------------------------------------------------------------------------------- 1 | [{"name": "chai aur python", "time": "50 min"}, {"name": "h", "time": "50"}] -------------------------------------------------------------------------------- /currency-converter/.gitignore: -------------------------------------------------------------------------------- 1 | exchange_rates_cache.json 2 | conversion_history.json 3 | *.pyc 4 | __pycache__/ 5 | -------------------------------------------------------------------------------- /qr-code-generator/qr_code_generator.py: -------------------------------------------------------------------------------- 1 | import qrcode 2 | 3 | qr = qrcode.QRCode( 4 | version=15, 5 | box_size=10, 6 | border=5 7 | ) 8 | 9 | data = input("Enter text or URL to convert to QR code: ") 10 | 11 | qr.add_data(data) 12 | qr.make(fit=True) 13 | img = qr.make_image(fill="black", back_color="white") 14 | filename = "qrcode.png" 15 | img.save(filename) 16 | print(f"QR code saved as {filename}") 17 | -------------------------------------------------------------------------------- /mini-games/ceasor_cypher.py: -------------------------------------------------------------------------------- 1 | def encypt_func(txt, s): 2 | result = "" 3 | 4 | 5 | # transverse the plain txt 6 | for i in range(len(txt)): 7 | char = txt[i] 8 | # encypt_func uppercase characters in plain txt 9 | 10 | if (char.isupper()): 11 | result += chr((ord(char) + s - 64) % 26 + 65) 12 | # encypt_func lowercase characters in plain txt 13 | else: 14 | result += chr((ord(char) + s - 96) % 26 + 97) 15 | return result 16 | # check the above function 17 | txt = "CEASER CIPHER EXAMPLE" 18 | s = 4 19 | 20 | print("Plain txt : " + txt) 21 | print("Shift pattern : " + str(s)) 22 | print("Cipher: " + encypt_func(txt, s)) -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # Python Mini Projects - Requirements 2 | # Install all dependencies with: pip install -r requirements.txt 3 | 4 | # Password Manager 5 | cryptography>=41.0.0 6 | 7 | # Expense Tracker 8 | matplotlib>=3.7.0 9 | 10 | # Currency Converter & Weather Detection 11 | requests>=2.31.0 12 | 13 | # Chatbot 14 | openai>=1.0.0 15 | 16 | # QR Code Generator 17 | qrcode>=7.4.0 18 | pillow>=10.0.0 19 | 20 | # Music Player 21 | pygame>=2.5.0 22 | 23 | # Language Translator 24 | translate>=3.6.0 25 | 26 | # Internet Speed Test 27 | speedtest-cli>=2.1.3 28 | 29 | # Note: Tkinter comes pre-installed with Python 30 | # Note: Some projects use only built-in libraries and have no external dependencies 31 | 32 | # Optional for environment variables 33 | python-dotenv>=1.0.0 34 | -------------------------------------------------------------------------------- /time-greeting/time_greeting.py: -------------------------------------------------------------------------------- 1 | 2 | import datetime 3 | 4 | current_time = datetime.datetime.now() 5 | 6 | print("The attributes of now() are :") 7 | 8 | print("Year :", current_time.year) 9 | 10 | print("Hour : ", current_time.hour) 11 | 12 | print("Minute : ", current_time.minute) 13 | 14 | print("Second :", current_time.second) 15 | 16 | def greeting_time(): 17 | currentTime = datetime.datetime.now() 18 | currentTime.hour 19 | print(currentTime.hour,":",currentTime.minute,":",currentTime.second,":",currentTime.microsecond) 20 | if currentTime.hour < 12: 21 | print('Good morning', "sir ") 22 | greeting=" good morning sir " 23 | elif 12 <= currentTime.hour < 18: 24 | print('Good afternoon', "sir") 25 | greeting="good afternoon sir " 26 | else: 27 | print('Good evening', "sir") 28 | greeting="good evening sir " 29 | 30 | greeting_time() 31 | 32 | -------------------------------------------------------------------------------- /qr-code-generator/README.md: -------------------------------------------------------------------------------- 1 | # QR Code Generator 2 | 3 | Generate QR codes from text or URLs. 4 | 5 | ## Features 6 | - 📱 Generate QR codes from any text or URL 7 | - 💾 Save QR codes as PNG images 8 | - 🎨 Customizable size and border 9 | - ⚡ Simple command-line interface 10 | 11 | ## Requirements 12 | ```bash 13 | pip install qrcode pillow 14 | ``` 15 | 16 | ## Usage 17 | ```bash 18 | python qr_code_generator.py 19 | ``` 20 | 21 | Enter your text or URL when prompted, and a QR code will be saved as `qrcode.png`. 22 | 23 | ## Example 24 | ``` 25 | Enter text or URL to convert to QR code: https://github.com 26 | QR code saved as qrcode.png 27 | ``` 28 | 29 | ## Customization 30 | You can modify the QR code settings in the code: 31 | - `version` - Size (1-40, higher = bigger) 32 | - `box_size` - Pixel size of each box 33 | - `border` - Border width in boxes 34 | - `fill` - QR code color 35 | - `back_color` - Background color 36 | -------------------------------------------------------------------------------- /text-editor/README.md: -------------------------------------------------------------------------------- 1 | # Text Editor 2 | 3 | Simple text editor with save functionality built with Tkinter. 4 | 5 | ## Features 6 | - 📝 Multi-line text editing 7 | - 💾 Save files as .txt 8 | - 📜 Scrollbar support 9 | - 🎨 Clean GUI interface 10 | 11 | ## Requirements 12 | No external packages required - uses built-in Tkinter. 13 | 14 | ## Usage 15 | ```bash 16 | python text_editor.py 17 | ``` 18 | 19 | ## Features 20 | - **Text Area** - Large scrollable text area for editing 21 | - **Save Button** - Save your work to a file 22 | - **File Dialog** - Choose save location and filename 23 | 24 | ## How to Use 25 | 1. Type or paste your text in the editor 26 | 2. Click the "Save" button 27 | 3. Choose location and filename 28 | 4. File will be saved as .txt 29 | 30 | ## Interface 31 | - Light grey header 32 | - White text area with scrollbar 33 | - Yellow save button at the bottom 34 | 35 | ## Future Enhancements 36 | - Open existing files 37 | - Font customization 38 | - Find and replace 39 | - Line numbers 40 | - Syntax highlighting 41 | -------------------------------------------------------------------------------- /rock-paper-scissors/rock-paper-scissor2.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | def get_user_choice(): 4 | choices = ['rock', 'paper', 'scissors'] 5 | choice = input("Enter rock, paper, or scissors: ").lower() 6 | while choice not in choices: 7 | print("Invalid choice. Try again.") 8 | choice = input("Enter rock, paper, or scissors: ").lower() 9 | return choice 10 | 11 | def get_computer_choice(): 12 | return random.choice(['rock', 'paper', 'scissors']) 13 | 14 | def determine_winner(user, computer): 15 | if user == computer: 16 | return "It's a tie!" 17 | elif (user == 'rock' and computer == 'scissors') or \ 18 | (user == 'scissors' and computer == 'paper') or \ 19 | (user == 'paper' and computer == 'rock'): 20 | return "You win!" 21 | else: 22 | return "Computer wins!" 23 | 24 | def play(): 25 | print("Welcome to Rock, Paper, Scissors!") 26 | user_choice = get_user_choice() 27 | computer_choice = get_computer_choice() 28 | print(f"You chose: {user_choice}") 29 | print(f"Computer chose: {computer_choice}") 30 | result = determine_winner(user_choice, computer_choice) 31 | print(result) 32 | 33 | if __name__ == "__main__": 34 | play() -------------------------------------------------------------------------------- /text-editor/text_editor.py: -------------------------------------------------------------------------------- 1 | from tkinter import * 2 | import tkinter as tk 3 | from tkinter.filedialog import asksaveasfilename 4 | 5 | 6 | stimulator_window = Tk() 7 | stimulator_window.geometry('600x600') 8 | stimulator_window.title('TEXT EDITOR') 9 | 10 | heading = Label(stimulator_window,text='Welcome to the Text Editor',font=('bold',20),bg='light grey') # This will creat a label for the heading. 11 | heading.pack() 12 | 13 | scrollbar = Scrollbar(stimulator_window) 14 | 15 | scrollbar.pack(side=RIGHT, 16 | fill=Y) 17 | 18 | 19 | text_info = Text(stimulator_window, 20 | yscrollcommand=scrollbar.set) 21 | text_info.pack(fill=BOTH) 22 | 23 | scrollbar.config(command=text_info.yview) 24 | 25 | def save(): 26 | filepath = asksaveasfilename(defaultextension="txt", filetypes=[("Text Files", "*.txt"), ("All Files", "*.*")]) 27 | if not filepath: 28 | return 29 | with open(filepath, "w") as output_file: 30 | text = text_info.get(1.0, tk.END) 31 | output_file.write(text) 32 | stimulator_window.title(f"Text Editor - {filepath}") 33 | 34 | button = Button(stimulator_window, text='Save', font=('normal', 10), command=save, bg='yellow') 35 | button.place(x=270,y=520) 36 | 37 | stimulator_window.mainloop() -------------------------------------------------------------------------------- /music-player/README.md: -------------------------------------------------------------------------------- 1 | # Music Player 2 | 3 | A GUI-based MP3 music player using Pygame and Tkinter. 4 | 5 | ## Features 6 | - 🎵 Play MP3 files 7 | - ⏸️ Pause/Resume playback 8 | - ⏹️ Stop playback 9 | - ➕ Add multiple songs to playlist 10 | - 🗑️ Delete songs from playlist 11 | - ⏭️ Next/Previous track navigation 12 | - 📝 Visual playlist display 13 | 14 | ## Requirements 15 | ```bash 16 | pip install pygame 17 | ``` 18 | 19 | ## Usage 20 | ```bash 21 | python music_player.py 22 | ``` 23 | 24 | ## Controls 25 | 1. **Add Songs** - Click to add MP3 files to playlist 26 | 2. **Delete Song** - Select a song and click to remove it 27 | 3. **Play** - Start playing selected song 28 | 4. **Pause** - Pause current playback 29 | 5. **Resume** - Resume paused song 30 | 6. **Stop** - Stop playback 31 | 7. **Previous** - Play previous song in list 32 | 8. **Next** - Play next song in list 33 | 34 | ## Interface 35 | - Black playlist display with white text 36 | - Easy-to-use button controls 37 | - Single-selection playlist 38 | - Automatic wraparound for next/previous 39 | 40 | ## Supported Formats 41 | - MP3 files (.mp3) 42 | - Can be extended to support other formats 43 | 44 | ## Tips 45 | - Add all your songs at once using file dialog 46 | - Select a song before playing 47 | - Use Previous/Next to navigate through playlist 48 | - Songs loop back to start/end when navigating 49 | -------------------------------------------------------------------------------- /rock-paper-scissors/README.md: -------------------------------------------------------------------------------- 1 | # Rock Paper Scissors 2 | 3 | Classic Rock Paper Scissors game against the computer. 4 | 5 | ## Features 6 | - 🎮 Play against computer AI 7 | - 🏆 First to 5 wins 8 | - 📊 Real-time score tracking 9 | - ✅ Input validation 10 | - 🎯 Clear game status display 11 | 12 | ## Requirements 13 | No external packages required - uses built-in Python libraries. 14 | 15 | ## Usage 16 | ```bash 17 | python rock_paper_scissors.py 18 | ``` 19 | 20 | ## How to Play 21 | 1. Choose your move: 22 | - 1 for Rock 23 | - 2 for Paper 24 | - 3 for Scissor 25 | 2. Computer makes its choice 26 | 3. Winner of round is determined 27 | 4. First to win 5 rounds wins the game! 28 | 29 | ## Game Rules 30 | - Rock beats Scissor 31 | - Scissor beats Paper 32 | - Paper beats Rock 33 | 34 | ## Example Session 35 | ``` 36 | === ROCK PAPER SCISSORS === 37 | 1 for rock 38 | 2 for paper 39 | 3 for scissor 40 | First to win 5 rounds wins the game! 41 | 42 | Enter your choice (1-3): 1 43 | You chose: Rock 44 | CPU chose: Scissor 45 | You win this round! Score: You 1 - 0 CPU 46 | 47 | Enter your choice (1-3): 2 48 | You chose: Paper 49 | CPU chose: Paper 50 | It's a tie! 51 | 52 | ... 53 | 54 | 🎉 YOU WIN THE GAME! Final Score: 5-3 55 | ``` 56 | 57 | ## Features 58 | - ✅ Input validation 59 | - ✅ Score tracking 60 | - ✅ Clear feedback 61 | - ✅ Handles ties 62 | - ✅ Professional formatting 63 | -------------------------------------------------------------------------------- /chatbot/README.md: -------------------------------------------------------------------------------- 1 | # Chatbot 2 | 3 | AI-powered chatbot using OpenAI's GPT-3.5 Turbo model. 4 | 5 | ## Features 6 | - 🤖 Conversational AI using GPT-3.5 Turbo 7 | - 💬 Maintains conversation context 8 | - 🔄 Updated for OpenAI API v1.0+ 9 | - 🔐 Secure API key handling via environment variables 10 | 11 | ## Requirements 12 | ```bash 13 | pip install openai 14 | ``` 15 | 16 | ## Setup 17 | 18 | 1. Get your OpenAI API key from: https://platform.openai.com/api-keys 19 | 20 | 2. Set the environment variable: 21 | ```bash 22 | export OPENAI_API_KEY='your-api-key-here' 23 | ``` 24 | 25 | Or on Windows: 26 | ```bash 27 | set OPENAI_API_KEY=your-api-key-here 28 | ``` 29 | 30 | ## Usage 31 | ```bash 32 | python chatbot.py 33 | ``` 34 | 35 | Type your messages and the AI will respond. Type 'exit', 'quit', or 'bye' to end the conversation. 36 | 37 | ## Example 38 | ``` 39 | AI CHATBOT 40 | 41 | You: Hello! 42 | Chatbot: Hello! How can I help you today? 43 | 44 | You: What is Python? 45 | Chatbot: Python is a high-level, interpreted programming language... 46 | 47 | You: exit 48 | Chatbot: Goodbye! Have a great day! 49 | ``` 50 | 51 | ## Features 52 | - ✅ Updated for latest OpenAI API (v1.0+) 53 | - ✅ Conversation history maintained 54 | - ✅ Error handling 55 | - ✅ Environment variable for API key (secure) 56 | - ✅ Simple command-line interface 57 | 58 | ## Note 59 | This requires an active OpenAI API key and will incur API usage costs. 60 | -------------------------------------------------------------------------------- /rock-paper-scissors/rock_paper_scissors.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | print("=== ROCK PAPER SCISSORS ===") 4 | print("1 for rock \n2 for paper \n3 for scissor") 5 | print("First to win 5 rounds wins the game!\n") 6 | 7 | def rock_paper_scissor(): 8 | i = 0 # CPU score 9 | j = 0 # Player score 10 | 11 | while i < 5 and j < 5: 12 | a = random.randint(1, 3) 13 | try: 14 | b = int(input("\nEnter your choice (1-3): ")) 15 | if b not in [1, 2, 3]: 16 | print("Invalid choice! Please enter 1, 2, or 3") 17 | continue 18 | except ValueError: 19 | print("Invalid input! Please enter a number") 20 | continue 21 | 22 | # Show choices 23 | choices = {1: "Rock", 2: "Paper", 3: "Scissor"} 24 | print(f"You chose: {choices[b]}") 25 | print(f"CPU chose: {choices[a]}") 26 | 27 | if a == b: 28 | print("It's a tie!") 29 | elif (a == 1 and b == 2) or (a == 2 and b == 3) or (a == 3 and b == 1): 30 | j += 1 31 | print(f"You win this round! Score: You {j} - {i} CPU") 32 | else: 33 | i += 1 34 | print(f"CPU wins this round! Score: You {j} - {i} CPU") 35 | 36 | print("\n" + "="*40) 37 | if j > i: 38 | print(f"🎉 YOU WIN THE GAME! Final Score: {j}-{i}") 39 | else: 40 | print(f"💻 CPU WINS THE GAME! Final Score: {i}-{j}") 41 | print("="*40) 42 | 43 | if __name__ == "__main__": 44 | rock_paper_scissor() -------------------------------------------------------------------------------- /weather-detection/README.md: -------------------------------------------------------------------------------- 1 | # Weather Detection 2 | 3 | Real-time weather information GUI application using OpenWeatherMap API. 4 | 5 | ## Features 6 | - 🌤️ Real-time weather data 7 | - 🌡️ Temperature display 8 | - 💨 Atmospheric pressure 9 | - 💧 Humidity levels 10 | - 📝 Weather description 11 | - 🎨 Colorful GUI interface 12 | 13 | ## Requirements 14 | ```bash 15 | pip install requests 16 | ``` 17 | 18 | ## Setup 19 | 20 | 1. Get your free API key from: https://openweathermap.org/api 21 | 22 | 2. Set the environment variable: 23 | ```bash 24 | export OPENWEATHER_API_KEY='your-api-key-here' 25 | ``` 26 | 27 | Or on Windows: 28 | ```bash 29 | set OPENWEATHER_API_KEY=your-api-key-here 30 | ``` 31 | 32 | ## Usage 33 | ```bash 34 | python weather_detection.py 35 | ``` 36 | 37 | ## How to Use 38 | 1. Enter a city name in the input field 39 | 2. Click the button to fetch weather data 40 | 3. View the weather information displayed 41 | 42 | ## Information Displayed 43 | - **Temperature** - Current temperature in Kelvin 44 | - **Pressure** - Atmospheric pressure in hPa 45 | - **Humidity** - Humidity percentage 46 | - **Description** - Weather condition description 47 | 48 | ## Interface 49 | - Light green background 50 | - Dark green labels 51 | - Red header 52 | - Entry fields for easy data display 53 | 54 | ## Error Handling 55 | - ✅ Invalid city name detection 56 | - ✅ API connection errors 57 | - ✅ Clear error messages 58 | 59 | ## Note 60 | - API key required (free tier available) 61 | - Internet connection required 62 | - Temperature shown in Kelvin (can be converted) 63 | -------------------------------------------------------------------------------- /language-translator/translator.py: -------------------------------------------------------------------------------- 1 | from tkinter import * 2 | from translate import Translator 3 | # initializing window 4 | Screen = Tk() 5 | Screen.title("Language Translator ") 6 | 7 | InputLanguageChoice = StringVar() 8 | TranslateLanguageChoice = StringVar() 9 | 10 | #tuple for choosing languages 11 | LanguageChoices = {'Hindi','English','French','German','Spanish'} 12 | InputLanguageChoice.set('English') 13 | TranslateLanguageChoice.set('French') 14 | 15 | def Translate(): 16 | translator = Translator(from_lang= InputLanguageChoice.get(),to_lang=TranslateLanguageChoice.get()) 17 | Translation = translator.translate(TextVar.get()) 18 | OutputVar.set(Translation) 19 | 20 | #choice for input language 21 | InputLanguageChoiceMenu = OptionMenu(Screen,InputLanguageChoice,*LanguageChoices) 22 | Label(Screen,text="Choose a Language").grid(row=0,column=1) 23 | InputLanguageChoiceMenu.grid(row=1,column=1) 24 | 25 | #choice in which the language is to be translated 26 | NewLanguageChoiceMenu = OptionMenu(Screen,TranslateLanguageChoice,*LanguageChoices) 27 | Label(Screen,text="Translated Language").grid(row=0,column=2) 28 | NewLanguageChoiceMenu.grid(row=1,column=2) 29 | 30 | Label(Screen,text="Enter Text").grid(row=2,column =0) 31 | TextVar = StringVar() 32 | TextBox = Entry(Screen,textvariable=TextVar).grid(row=2,column = 1) 33 | 34 | Label(Screen,text="Output Text").grid(row=2,column =2) 35 | OutputVar = StringVar() 36 | TextBox = Entry(Screen,textvariable=OutputVar).grid(row=2,column = 3) 37 | 38 | #Button for calling function 39 | B = Button(Screen,text="Translate",command=Translate, relief = GROOVE).grid(row=3,column=1,columnspan = 3) 40 | 41 | mainloop() 42 | -------------------------------------------------------------------------------- /chatbot/chatbot.py: -------------------------------------------------------------------------------- 1 | import os 2 | try: 3 | from openai import OpenAI 4 | except ImportError: 5 | print("Error: openai package not installed. Install with: pip install openai") 6 | exit(1) 7 | 8 | # Get API key from environment variable 9 | api_key = os.environ.get('OPENAI_API_KEY') 10 | 11 | if not api_key: 12 | print("Error: OPENAI_API_KEY environment variable not set") 13 | print("Set it with: export OPENAI_API_KEY='your-api-key-here'") 14 | exit(1) 15 | 16 | # Initialize OpenAI client (updated for v1.0+) 17 | client = OpenAI(api_key=api_key) 18 | 19 | # Conversation history 20 | conversation_history = [ 21 | {"role": "system", "content": "You are a helpful chatbot."} 22 | ] 23 | 24 | def chat_with_gpt(user_input): 25 | """Send message to ChatGPT and get response""" 26 | # Add user message to history 27 | conversation_history.append({"role": "user", "content": user_input}) 28 | 29 | try: 30 | # Use updated API (openai v1.0+) 31 | response = client.chat.completions.create( 32 | model="gpt-3.5-turbo", 33 | messages=conversation_history 34 | ) 35 | 36 | # Extract assistant's reply 37 | assistant_reply = response.choices[0].message.content 38 | 39 | # Add to conversation history 40 | conversation_history.append({"role": "assistant", "content": assistant_reply}) 41 | 42 | return assistant_reply 43 | except Exception as e: 44 | return f"Error: {str(e)}" 45 | 46 | # Start a conversation with the chatbot 47 | print("="*50) 48 | print("AI CHATBOT".center(50)) 49 | print("="*50) 50 | print("Type 'exit', 'quit', or 'bye' to end the conversation\n") 51 | 52 | while True: 53 | user_input = input("You: ").strip() 54 | 55 | if user_input.lower() in ['exit', 'quit', 'bye']: 56 | print("Chatbot: Goodbye! Have a great day!") 57 | break 58 | 59 | if not user_input: 60 | continue 61 | 62 | response = chat_with_gpt(user_input) 63 | print(f"Chatbot: {response}\n") -------------------------------------------------------------------------------- /password-manager/README.md: -------------------------------------------------------------------------------- 1 | # Password Manager 2 | 3 | A secure command-line password manager that encrypts and stores your passwords safely. 4 | 5 | ## Features 6 | - 🔐 **Master Password Protection** - Secure access with a master password 7 | - 🔒 **Military-Grade Encryption** - Uses Fernet symmetric encryption 8 | - ➕ **Add Passwords** - Store passwords for different accounts 9 | - 👀 **View Passwords** - View all stored passwords (decrypted) 10 | - 🔍 **Search Functionality** - Quickly find passwords by account name 11 | - 🗑️ **Delete Passwords** - Remove passwords you no longer need 12 | - 💾 **Persistent Storage** - Data saved in encrypted JSON format 13 | 14 | ## Requirements 15 | ```bash 16 | pip install cryptography 17 | ``` 18 | 19 | ## Usage 20 | ```bash 21 | python password_manager.py 22 | ``` 23 | 24 | ### First Time Setup 25 | 1. Run the program 26 | 2. Create a master password (you'll need this every time) 27 | 3. Start adding your passwords 28 | 29 | ### Menu Options 30 | 1. **Add New Password** - Store a new account password 31 | 2. **View All Passwords** - Display all stored passwords 32 | 3. **Search Password** - Find a specific password 33 | 4. **Delete Password** - Remove a password entry 34 | 5. **Exit** - Close the program 35 | 36 | ## Security Features 37 | - Master password hashed with SHA-256 38 | - Passwords encrypted with Fernet (symmetric encryption) 39 | - Password input hidden (not displayed on screen) 40 | - Encryption key stored separately 41 | - 3 attempts limit for master password 42 | 43 | ## Files Created 44 | - `passwords.json` - Encrypted password storage 45 | - `key.key` - Encryption key (keep this safe!) 46 | - `master.hash` - Hashed master password 47 | 48 | ## ⚠️ Important Notes 49 | - **Never share your master password** 50 | - **Backup `key.key` file** - Without it, passwords cannot be decrypted 51 | - **Keep files secure** - Don't commit these files to public repositories 52 | 53 | ## Example Usage 54 | ``` 55 | Enter master password: **** 56 | ✓ Access granted! 57 | 58 | === Add New Password === 59 | Account/Website name: Gmail 60 | Username/Email: user@gmail.com 61 | Password: **** 62 | ✓ Password for 'Gmail' saved successfully! 63 | ``` 64 | -------------------------------------------------------------------------------- /morse-code-translator/morse_translator.py: -------------------------------------------------------------------------------- 1 | 2 | # Morse code dictionary: 3 | MORSE_CODE_DICT = { 4 | 'A': '.-', 'B': '-...', 'C': '-.-.', 'D': '-..', 5 | 'E': '.', 'F': '..-.', 'G': '--.', 'H': '....', 6 | 'I': '..', 'J': '.---', 'K': '-.-', 'L': '.-..', 7 | 'M': '--', 'N': '-.', 'O': '---', 'P': '.--.', 8 | 'Q': '--.-', 'R': '.-.', 'S': '...', 'T': '-', 9 | 'U': '..-', 'V': '...-', 'W': '.--', 'X': '-..-', 10 | 'Y': '-.--', 'Z': '--..', 11 | '0': '-----', '1': '.----', '2': '..---', '3': '...--', 12 | '4': '....-', '5': '.....', '6': '-....', '7': '--...', 13 | '8': '---..', '9': '----.' 14 | } 15 | 16 | REVERSE_MORSE_CODE_DICT = {v: k for k, v in MORSE_CODE_DICT.items()} 17 | 18 | def encode_to_morse(text): 19 | text = text.upper() 20 | morse_code = [] 21 | for char in text: 22 | if char == ' ': 23 | morse_code.append(' ') # Separate words by space 24 | elif char in MORSE_CODE_DICT: 25 | morse_code.append(MORSE_CODE_DICT[char]) 26 | else: 27 | morse_code.append('?') # Unknown characters 28 | return ' '.join(morse_code) 29 | 30 | def decode_from_morse(morse): 31 | words = morse.split(' ') # Morse words separated by 3 spaces 32 | decoded_words = [] 33 | for word in words: 34 | letters = word.split() 35 | decoded_letters = [] 36 | for letter in letters: 37 | decoded_letters.append(REVERSE_MORSE_CODE_DICT.get(letter, '?')) 38 | decoded_words.append(''.join(decoded_letters)) 39 | return ' '.join(decoded_words) 40 | 41 | print("Morse Code Translator") 42 | choice = input("Type 'E' to encode text to Morse or 'D' to decode Morse to text: ").strip().upper() 43 | 44 | if choice == 'E': 45 | text = input("Enter the text to encode: ") 46 | encoded = encode_to_morse(text) 47 | print(f"Encoded Morse:\n{encoded}") 48 | 49 | elif choice == 'D': 50 | print("Note: Separate Morse letters with spaces and words with 3 spaces.") 51 | morse = input("Enter the Morse code to decode: ") 52 | decoded = decode_from_morse(morse) 53 | print(f"Decoded Text:\n{decoded}") 54 | 55 | else: 56 | print("Invalid choice. Please run the program again and type 'E' or 'D'.") 57 | -------------------------------------------------------------------------------- /typing-speed-test/typing_speed_test.py: -------------------------------------------------------------------------------- 1 | import time 2 | import random 3 | print("Welcome to the Typing Speed and Accuracy Test!") 4 | print("You will be prompted to type a random sentence. Ready? Go!\n") 5 | a=["India is the seventh-largest country in the world by land area.", 6 | "The capital of India is New Delhi and the official language is Hindi.", 7 | "India is known for its rich cultural heritage, with over 2,000 ethnic groups and more than 1,600 languages spoken across the country.", 8 | "The Indian economy is the fifth-largest in the world by nominal GDP and the third-largest by purchasing power parity." 9 | "The Indian subcontinent is home to many iconic landmarks and tourist destinations, such as the Taj Mahal, the Golden Temple, and the Himalayas." 10 | "The national animal of India is the Bengal tiger and the national bird is the peacock.", 11 | "The country has a rich history of arts, literature, and music, with classical dance forms such as Bharatanatyam and Kathak, and traditional musical instruments like the sitar and tabla.", 12 | "Indian cuisine is known for its diverse flavors and spices, with popular dishes such as butter chicken, biryani, and samosas.", 13 | "India has a large film industry known as Bollywood, which produces thousands of movies each year in Hindi and other regional languages.", 14 | "Mahatma Gandhi, who led India to independence from British rule, is widely regarded as one of the most influential figures in modern history."] 15 | b= random.randint(0,9) 16 | sentence = a[b] 17 | print(sentence) 18 | 19 | start_time = time.time() 20 | user_input = input() 21 | end_time = time.time() 22 | 23 | time_taken = end_time - start_time 24 | num_chars = len(user_input) 25 | 26 | # Calculate typing speed and accuracy 27 | typing_speed = num_chars / time_taken 28 | correct_chars = sum([1 for i in range(num_chars) if user_input[i] == sentence[i]]) 29 | accuracy = (correct_chars / num_chars) * 100 30 | 31 | print(f"\nYou typed: '{user_input}'") 32 | print(f"Time taken: {time_taken:.2f} seconds") 33 | print(f"Your typing speed: {typing_speed:.2f} characters per second") 34 | print(f"Accuracy: {accuracy:.2f}%") 35 | 36 | type_speed = int((typing_speed*accuracy)/100) 37 | print(f"Your typing speed: {type_speed} characters per second") -------------------------------------------------------------------------------- /expense-tracker/README.md: -------------------------------------------------------------------------------- 1 | # Expense Tracker 💰 2 | 3 | Track your daily expenses with detailed reports and beautiful visualizations. 4 | 5 | ## Features 6 | - 📝 **Add Expenses** - Record expenses with description, category, amount, and date 7 | - 👀 **View All Expenses** - Display all recorded expenses in a table format 8 | - 🔍 **Filter by Category** - View expenses filtered by specific categories 9 | - 📊 **Monthly Summary** - Get detailed monthly expense breakdowns 10 | - 📈 **Visualizations** - Create charts (pie, line, bar) to analyze spending patterns 11 | - 💾 **Export to CSV** - Export your expense data for external analysis 12 | - 🗑️ **Delete Expenses** - Remove incorrect entries 13 | - 🎯 **9 Categories** - Pre-defined categories for easy organization 14 | 15 | ## Categories 16 | 1. Food & Dining 17 | 2. Transportation 18 | 3. Shopping 19 | 4. Entertainment 20 | 5. Bills & Utilities 21 | 6. Healthcare 22 | 7. Education 23 | 8. Travel 24 | 9. Other 25 | 26 | ## Requirements 27 | ```bash 28 | pip install matplotlib 29 | ``` 30 | 31 | ## Usage 32 | ```bash 33 | python expense_tracker.py 34 | ``` 35 | 36 | ## Features in Detail 37 | 38 | ### Add Expense 39 | Record new expenses with: 40 | - Description (e.g., "Grocery shopping") 41 | - Category (from predefined list) 42 | - Amount in dollars 43 | - Date (default: today) 44 | 45 | ### Monthly Summary 46 | - View total spending per category 47 | - See percentage breakdown 48 | - Identify top spending categories 49 | 50 | ### Visualizations 51 | 1. **Pie Chart** - Shows spending distribution by category 52 | 2. **Line Chart** - Tracks daily spending over time 53 | 3. **Bar Chart** - Compares monthly spending 54 | 55 | ### Export to CSV 56 | Export all expenses to CSV format with: 57 | - Date, Description, Category, Amount 58 | - Timestamped filename 59 | - Compatible with Excel/Google Sheets 60 | 61 | ## Example Usage 62 | ``` 63 | === ADD NEW EXPENSE === 64 | Description: Lunch at restaurant 65 | Category: 1 (Food & Dining) 66 | Amount ($): 25.50 67 | Date: 2025-10-15 68 | 69 | ✓ Expense added successfully! ($25.50 for Food & Dining) 70 | ``` 71 | 72 | ## Files Created 73 | - `expenses.json` - Stores all expense data 74 | - `expenses_export_*.csv` - Exported CSV files 75 | 76 | ## Tips 77 | - 💡 Add expenses daily for accurate tracking 78 | - 📊 Review monthly summaries to identify spending patterns 79 | - 🎯 Use categories consistently for better analysis 80 | - 📈 Check visualizations monthly to spot trends 81 | -------------------------------------------------------------------------------- /youtube-video-manager/youtube_manager.py: -------------------------------------------------------------------------------- 1 | 2 | import json 3 | 4 | def load_data(): 5 | try: 6 | with open('youtube.txt', 'r') as file: 7 | test = json.load(file) 8 | # print(type(test)) 9 | return test 10 | except FileNotFoundError: 11 | return [] 12 | 13 | def save_data_helper(videos): 14 | with open('youtube.txt', 'w') as file: 15 | json.dump(videos, file) 16 | 17 | def list_all_videos(videos): 18 | print("\n") 19 | print("*" * 70) 20 | for index, video in enumerate(videos, start=1): 21 | print(f"{index}. {video['name']}, Duration: {video['time']} ") 22 | print("\n") 23 | print("*" * 70) 24 | 25 | def add_video(videos): 26 | name = input("Enter video name: ") 27 | time = input("Enter video time: ") 28 | videos.append({'name': name, 'time': time}) 29 | save_data_helper(videos) 30 | 31 | def update_video(videos): 32 | list_all_videos(videos) 33 | index = int(input("Enter the video number to update")) 34 | if 1 <= index <= len(videos): 35 | name = input("Enter the new video name") 36 | time = input("Enter the new video time") 37 | videos[index-1] = {'name':name, 'time': time} 38 | save_data_helper(videos) 39 | else: 40 | print("Invalid index selected") 41 | 42 | 43 | def delete_video(videos): 44 | list_all_videos(videos) 45 | index = int(input("Enter the video number to be deleted")) 46 | 47 | if 1<= index <= len(videos): 48 | del videos[index-1] 49 | save_data_helper(videos) 50 | else: 51 | print("Invalid video index selected") 52 | 53 | 54 | def main(): 55 | videos = load_data() 56 | while True: 57 | print("\n Youtube Manager | choose an option ") 58 | print("1. List all youtube videos ") 59 | print("2. Add a youtube video ") 60 | print("3. Update a youtube video details ") 61 | print("4. Delete a youtube video ") 62 | print("5. Exit the app ") 63 | choice = input("Enter your choice: ") 64 | # print(videos) 65 | 66 | match choice: 67 | case '1': 68 | list_all_videos(videos) 69 | case '2': 70 | add_video(videos) 71 | case '3': 72 | update_video(videos) 73 | case '4': 74 | delete_video(videos) 75 | case '5': 76 | break 77 | case _: 78 | print("Invalid Choice") 79 | 80 | if __name__ == "__main__": 81 | main() 82 | 83 | -------------------------------------------------------------------------------- /pomodoro-timer/README.md: -------------------------------------------------------------------------------- 1 | # Pomodoro Timer 🍅 2 | 3 | A beautiful productivity timer based on the Pomodoro Technique with GUI interface. 4 | 5 | ## What is Pomodoro Technique? 6 | The Pomodoro Technique is a time management method that uses a timer to break work into intervals: 7 | - **25 minutes** of focused work 8 | - **5 minutes** short break 9 | - **15 minutes** long break (after 4 sessions) 10 | 11 | ## Features 12 | - ⏱️ **Visual Timer** - Large, easy-to-read countdown display 13 | - 🎨 **Beautiful GUI** - Modern interface with color-coded sessions 14 | - 📊 **Progress Bar** - Visual representation of session progress 15 | - 🔔 **Sound Notifications** - Audio alerts when sessions complete 16 | - 📈 **Statistics Tracking** - Track daily sessions and total time 17 | - ⏸️ **Pause/Resume** - Pause timer when needed 18 | - ⏭️ **Skip Sessions** - Skip current session if needed 19 | - 🔄 **Auto-cycling** - Automatically switches between work and breaks 20 | 21 | ## Requirements 22 | ```bash 23 | # No external packages required - uses built-in tkinter 24 | # Sound notifications use winsound (Windows) or system beep 25 | ``` 26 | 27 | ## Usage 28 | ```bash 29 | python pomodoro_timer.py 30 | ``` 31 | 32 | ## How to Use 33 | 1. **Click START** to begin a 25-minute work session 34 | 2. **Focus on your task** until the timer completes 35 | 3. **Take a break** when the timer alerts you 36 | 4. **Repeat** for maximum productivity 37 | 38 | ## Session Types 39 | - 🔴 **Work Session** (25 min) - Focus time 40 | - 🔵 **Short Break** (5 min) - Quick rest after each session 41 | - 🟣 **Long Break** (15 min) - Extended rest after 4 sessions 42 | 43 | ## Controls 44 | - **▶ START/PAUSE** - Start or pause the timer 45 | - **⟲ RESET** - Reset current session to beginning 46 | - **⏭ SKIP** - Skip to next session 47 | 48 | ## Statistics 49 | The app tracks: 50 | - Number of sessions completed today 51 | - Total focused time today 52 | - Historical data saved in `pomodoro_stats.json` 53 | 54 | ## Color Coding 55 | - **Red** - Work session (focus time) 56 | - **Blue** - Short break 57 | - **Purple** - Long break 58 | 59 | ## Tips for Best Results 60 | - 💪 Eliminate distractions during work sessions 61 | - 🚫 Don't check phone or emails during focus time 62 | - ☕ Use breaks to move, stretch, or rest your eyes 63 | - 📝 Plan tasks before starting timer 64 | - 🎯 Aim for 4-8 pomodoros per day 65 | 66 | ## Files Created 67 | - `pomodoro_stats.json` - Daily statistics and history 68 | 69 | ## Benefits 70 | - ✅ Improved focus and concentration 71 | - ✅ Better time management 72 | - ✅ Reduced mental fatigue 73 | - ✅ Increased productivity 74 | - ✅ Better work-life balance 75 | -------------------------------------------------------------------------------- /mini-games/black_jack.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | card_categories = ['Hearts', 'Diamonds', 'Clubs', 'Spades'] 4 | cards_list = ['Ace', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'Jack', 'Queen', 'King'] 5 | deck = [(card, category) for category in card_categories for card in cards_list] 6 | 7 | def card_value(card): 8 | if card[0] in ['Jack', 'Queen', 'King']: 9 | return 10 10 | elif card[0] == 'Ace': 11 | return 11 12 | else: 13 | return int(card[0]) 14 | 15 | random.shuffle(deck) 16 | player_card = [deck.pop(), deck.pop()] 17 | dealer_card = [deck.pop(), deck.pop()] 18 | 19 | while True: 20 | player_score = sum(card_value(card) for card in player_card) 21 | dealer_score = sum(card_value(card) for card in dealer_card) 22 | print("Cards Player Has:", player_card) 23 | print("Score Of The Player:", player_score) 24 | print("\n") 25 | choice = input('What do you want? ["play" to request another card, "stop" to stop]: ').lower() 26 | if choice == "play": 27 | new_card = deck.pop() 28 | player_card.append(new_card) 29 | elif choice == "stop": 30 | break 31 | else: 32 | print("Invalid choice. Please try again.") 33 | continue 34 | 35 | if player_score > 21: 36 | print("Cards Dealer Has:", dealer_card) 37 | print("Score Of The Dealer:", dealer_score) 38 | print("Cards Player Has:", player_card) 39 | print("Score Of The Player:", player_score) 40 | print("Dealer wins (Player Loss Because Player Score is exceeding 21)") 41 | break 42 | 43 | while dealer_score < 17: 44 | new_card = deck.pop() 45 | dealer_card.append(new_card) 46 | dealer_score += card_value(new_card) 47 | 48 | print("Cards Dealer Has:", dealer_card) 49 | print("Score Of The Dealer:", dealer_score) 50 | print("\n") 51 | 52 | if dealer_score > 21: 53 | print("Cards Dealer Has:", dealer_card) 54 | print("Score Of The Dealer:", dealer_score) 55 | print("Cards Player Has:", player_card) 56 | print("Score Of The Player:", player_score) 57 | print("Player wins (Dealer Loss Because Dealer Score is exceeding 21)") 58 | elif player_score > dealer_score: 59 | print("Cards Dealer Has:", dealer_card) 60 | print("Score Of The Dealer:", dealer_score) 61 | print("Cards Player Has:", player_card) 62 | print("Score Of The Player:", player_score) 63 | print("Player wins (Player Has High Score than Dealer)") 64 | elif dealer_score > player_score: 65 | print("Cards Dealer Has:", dealer_card) 66 | print("Score Of The Dealer:", dealer_score) 67 | print("Cards Player Has:", player_card) 68 | print("Score Of The Player:", player_score) 69 | print("Dealer wins (Dealer Has High Score than Player)") 70 | else: 71 | print("Cards Dealer Has:", dealer_card) 72 | print("Score Of The Dealer:", dealer_score) 73 | print("Cards Player Has:", player_card) 74 | print("Score Of The Player:", player_score) 75 | print("It's a tie.") 76 | -------------------------------------------------------------------------------- /internet-speed-test/internet_speed_test.py: -------------------------------------------------------------------------------- 1 | from tkinter import* 2 | from PIL import ImageTk,Image 3 | from tkinter import messagebox 4 | import tkinter 5 | import speedtest 6 | 7 | a=0 8 | b=0 9 | c=0 10 | 11 | 12 | def check(): 13 | st = speedtest.Speedtest() 14 | a=st.download() 15 | b=st.upload() 16 | print("Download speed = ",a/500000,"Mbps") 17 | print("Uplode speed = ",b/500000,"Mbps") 18 | server_names = [] 19 | st.get_servers(server_names) 20 | c=st.results.ping 21 | print(c,"ms") 22 | speed_test(a,b,c) 23 | 24 | def speed_test(a,b,c): 25 | e=int(a/500000) 26 | f=int(b/500000) 27 | g=int(c) 28 | d=int ((e+f)/2) 29 | root = Tk() 30 | root.title('speed Testing') 31 | root.geometry('400x650') 32 | root.configure(bg='white') 33 | ####icon 34 | 35 | #######image_______ 36 | download=Label(root,text='SPEED TEST ',font="arial 30 bold ",bg="red",fg='white').place(x=70,y=30) 37 | 38 | #######Label1_____________ 39 | download2=Label(root,text='Your internet speed is ',font="arial 17 bold ",bg="white").place(x=60,y=90) 40 | Label(root,text=d,font="arial 110 bold",bg="white").place(x=80,y=260) 41 | Label(root,text='Mbps',font="arial 22 bold ",bg="white").place(x=255,y=260) 42 | #######Label2__________ 43 | 44 | Label(root,text='Latency',font="arial 15 bold ",bg="white").place(x=50,y=430) 45 | Label(root,text='Uplod ',font="arial 15 bold ",bg="white").place(x=250,y=430) 46 | ####Label3____________ 47 | Label(root,text='Upload ',font="arial 12 normal ",bg="white").place(x=50,y=470) 48 | Label(root,text='Download ',font="arial 12 normal ",bg="white").place(x=150,y=470) 49 | Label(root,text='Ping ',font="arial 12 normal ",bg="white").place(x=250,y=470) 50 | ########Label4___________ 51 | unloaded=Label(root,text=e,font="arial 20 bold ",bg="white") 52 | unloaded.place(x=50,y=500) 53 | loaded=Label(root,text=f,font="arial 20 bold ",bg="white") 54 | loaded.place(x=150,y=500) 55 | speed=Label(root,text=g,font="arial 20 bold ",bg="white") 56 | speed.place(x=250,y=500) 57 | #######Label5________________ 58 | unloaded1=Label(root,text='Mbps ',font="arial 10 normal ",bg="white") 59 | unloaded1.place(x=83,y=511) 60 | loaded1=Label(root,text='Mbps',font="arial 10 normal ",bg="white") 61 | loaded1.place(x=183,y=511) 62 | speed1=Label(root,text='ms ',font="arial 10 normal ",bg="white") 63 | speed1.place(x=290,y=511) 64 | 65 | #button 66 | Button2=Button(root,text="Run Speed Test",bg='sky blue',font="arial 18 bold",bd=0,activebackground='white',cursor='cross',command=check) 67 | Button2.place(x=85,y=560) 68 | 69 | #########label7_____________________ 70 | Label1=Label(root,text='Power by - ',font="arial 12 bold ",bg="white") 71 | Label1.place(x=70,y=620) 72 | Label2=Label(root,text='Chirag Joshi ',font="arial 13 bold ",bg="white",fg='red') 73 | Label2.place(x=160,y=620) 74 | root.mainloop() 75 | 76 | speed_test(a,b,c) -------------------------------------------------------------------------------- /weather-detection/weather_detection.py: -------------------------------------------------------------------------------- 1 | from tkinter import * 2 | from tkinter import messagebox 3 | 4 | def tell_weather(): 5 | 6 | import requests 7 | import json 8 | import os 9 | 10 | # Get API key from environment variable or use placeholder 11 | api_key = os.environ.get('OPENWEATHER_API_KEY', 'Your_API_key') 12 | 13 | if api_key == 'Your_API_key': 14 | messagebox.showwarning("API Key Required", 15 | "Please set OPENWEATHER_API_KEY environment variable.\n" 16 | "Get your free API key from: https://openweathermap.org/api") 17 | return 18 | 19 | base_url = "http://api.openweathermap.org/data/2.5/weather?" 20 | 21 | city_name = city_field.get() 22 | 23 | complete_url = base_url + "appid=" + api_key + "&q=" + city_name 24 | 25 | 26 | response = requests.get(complete_url) 27 | 28 | x = response.json() 29 | if x["cod"] != "404" : 30 | 31 | y = x["main"] 32 | 33 | current_temperature = y["temp"] 34 | 35 | current_pressure = y["pressure"] 36 | 37 | current_humidity = y["humidity"] 38 | 39 | z = x["weather"] 40 | 41 | weather_description = z[0]["description"] 42 | 43 | temp_field.insert(15, str(current_temperature) + " Kelvin") 44 | atm_field.insert(10, str(current_pressure) + " hPa") 45 | humid_field.insert(15, str(current_humidity) + " %") 46 | desc_field.insert(10, str(weather_description) ) 47 | 48 | else : 49 | 50 | messagebox.showerror("Error", "City Not Found \n" 51 | "Please enter valid city name") 52 | 53 | city_field.delete(0, END) 54 | 55 | 56 | 57 | def clear_all() : 58 | city_field.delete(0, END) 59 | temp_field.delete(0, END) 60 | atm_field.delete(0, END) 61 | humid_field.delete(0, END) 62 | desc_field.delete(0, END) 63 | 64 | city_field.focus_set() 65 | 66 | 67 | if __name__ == "__main__" : 68 | 69 | root = Tk() 70 | 71 | root.title("Gui Application") 72 | 73 | root.configure(background = "light green") 74 | 75 | root.geometry("425x175") 76 | 77 | headlabel = Label(root, text = "Weather Gui Application", 78 | fg = 'black', bg = 'red') 79 | 80 | label1 = Label(root, text = "City name : ", 81 | fg = 'black', bg = 'dark green') 82 | 83 | label2 = Label(root, text = "Temperature :", 84 | fg = 'black', bg = 'dark green') 85 | 86 | label3 = Label(root, text = "atm pressure :", 87 | fg = 'black', bg = 'dark green') 88 | 89 | label4 = Label(root, text = "humidity :", 90 | fg = 'black', bg = 'dark green') 91 | 92 | label5 = Label(root, text = "description :", 93 | fg = 'black', bg = 'dark green') 94 | 95 | 96 | headlabel.grid(row = 0, column = 1) 97 | label1.grid(row = 1, column = 0, sticky ="E") 98 | label2.grid(row = 3, column = 0, sticky ="E") 99 | label3.grid(row = 4, column = 0, sticky ="E") 100 | label4.grid(row = 5, column = 0, sticky ="E") 101 | label5.grid(row = 6, column = 0, sticky ="E") 102 | 103 | 104 | city_field = Entry(root) 105 | temp_field = Entry(root) 106 | atm_field = Entry(root) 107 | humid_field = Entry(root) 108 | desc_field = Entry(root) 109 | 110 | city_field.grid(row = 1, column = 1, ipadx ="100") 111 | temp_field.grid(row = 3, column = 1, ipadx ="100") 112 | atm_field.grid(row = 4, column = 1, ipadx ="100") 113 | humid_field.grid(row = 5, column = 1, ipadx ="100") 114 | desc_field.grid(row = 6, column = 1, ipadx ="100") 115 | 116 | button1 = Button(root, text = "Submit", bg = "red", 117 | fg = "black", command = tell_weather) 118 | 119 | 120 | button2 = Button(root, text = "Clear", bg = "red", 121 | fg = "black", command = clear_all) 122 | 123 | 124 | button1.grid(row = 2, column = 1) 125 | button2.grid(row = 7, column = 1) 126 | 127 | root.mainloop() 128 | -------------------------------------------------------------------------------- /currency-converter/README.md: -------------------------------------------------------------------------------- 1 | # Currency Converter 💱 2 | 3 | Real-time currency converter with beautiful GUI supporting 150+ currencies. 4 | 5 | ## Features 6 | - 💱 **Real-Time Rates** - Live exchange rates from API 7 | - 🌍 **150+ Currencies** - Support for major world currencies 8 | - 💾 **Smart Caching** - Offline mode with 6-hour cache 9 | - 🔄 **Quick Swap** - Easily swap between currencies 10 | - 📜 **Conversion History** - Track past conversions 11 | - ⚡ **Quick Convert** - See popular currency rates at a glance 12 | - 🎨 **Beautiful GUI** - Modern, user-friendly interface 13 | - 📊 **Exchange Rate Display** - Shows current rate for transparency 14 | 15 | ## Requirements 16 | ```bash 17 | pip install requests 18 | ``` 19 | 20 | ## Usage 21 | ```bash 22 | python currency_converter.py 23 | ``` 24 | 25 | ## How to Use 26 | 27 | 1. **Enter Amount** - Type the amount you want to convert 28 | 2. **Select From Currency** - Choose source currency from dropdown 29 | 3. **Select To Currency** - Choose target currency 30 | 4. **Click Convert** - See the result instantly! 31 | 32 | ### Quick Swap 33 | Click the **⇅** button to quickly swap between currencies. 34 | 35 | ### Refresh Rates 36 | Click **🔃 Refresh Rates** to fetch the latest exchange rates. 37 | 38 | ### View History 39 | Click **📜 History** to see your last 50 conversions. 40 | 41 | ## Supported Currency Examples 42 | - 🇺🇸 USD - US Dollar 43 | - 🇪🇺 EUR - Euro 44 | - 🇬🇧 GBP - British Pound 45 | - 🇯🇵 JPY - Japanese Yen 46 | - 🇮🇳 INR - Indian Rupee 47 | - 🇨🇦 CAD - Canadian Dollar 48 | - 🇦🇺 AUD - Australian Dollar 49 | - 🇨🇭 CHF - Swiss Franc 50 | - 🇨🇳 CNY - Chinese Yuan 51 | - 🇲🇽 MXN - Mexican Peso 52 | - ...and 140+ more! 53 | 54 | ## Features in Detail 55 | 56 | ### Real-Time Exchange Rates 57 | - Fetches live rates from ExchangeRate-API 58 | - No API key required 59 | - Updates automatically 60 | 61 | ### Smart Caching 62 | - Caches rates for 6 hours 63 | - Works offline with cached data 64 | - Shows last update time 65 | - Reduces API calls 66 | 67 | ### Quick Convert Panel 68 | Shows live conversion rates for 1 USD to popular currencies: 69 | - EUR, GBP, JPY, AUD, INR 70 | 71 | ### Conversion History 72 | - Stores last 50 conversions 73 | - Shows timestamp for each conversion 74 | - Displays amount, currencies, and exchange rate 75 | - Persistent across sessions 76 | 77 | ## Example Conversion 78 | ``` 79 | Amount: 100.00 80 | From: USD 🇺🇸 81 | To: EUR 🇪🇺 82 | 83 | Result: 100.00 USD = 92.15 EUR 84 | Exchange Rate: 1 USD = 0.9215 EUR 85 | ``` 86 | 87 | ## API Information 88 | This app uses the free ExchangeRate-API (https://exchangerate-api.com/) 89 | - No API key required for basic usage 90 | - 1,500 requests per month (free tier) 91 | - Rates updated daily 92 | 93 | ## Files Created 94 | - `exchange_rates_cache.json` - Cached exchange rates 95 | - `conversion_history.json` - Your conversion history 96 | 97 | ## Offline Mode 98 | The app works offline using cached exchange rates if: 99 | - You've used it before (cache exists) 100 | - Cache is less than 6 hours old 101 | - Internet connection is unavailable 102 | 103 | ## Tips 104 | - 💡 Use swap button for quick currency reversal 105 | - 🔄 Refresh rates daily for accuracy 106 | - 📊 Check history to track exchange rate trends 107 | - 💾 App works offline with cached rates 108 | - 🎯 Use quick convert panel for common currencies 109 | 110 | ## Error Handling 111 | - ✅ Validates numeric input 112 | - ✅ Handles API failures gracefully 113 | - ✅ Falls back to cached rates 114 | - ✅ Clear error messages 115 | - ✅ Prevents invalid conversions 116 | 117 | ## Use Cases 118 | - 💼 Business currency conversions 119 | - ✈️ Travel planning 120 | - 🛒 International shopping 121 | - 💰 Investment tracking 122 | - 📈 Exchange rate monitoring 123 | -------------------------------------------------------------------------------- /music-player/music_player.py: -------------------------------------------------------------------------------- 1 | from pygame import mixer 2 | from tkinter import * 3 | import tkinter.font as font 4 | from tkinter import filedialog 5 | 6 | root=Tk() 7 | root.title(' music plyer ') 8 | mixer.init() 9 | 10 | 11 | songs_list=Listbox(root,selectmode=SINGLE,bg="black",fg="white",font=('arial',15),height=12,width=47,selectbackground="gray",selectforeground="black") 12 | songs_list.grid(columnspan=9) 13 | 14 | 15 | def addsongs(): 16 | temp_song = filedialog.askopenfilenames(initialdir="~/", title="Choose a song", filetypes=(("mp3 Files", "*.mp3"), ("All Files", "*.*"))) 17 | for s in temp_song: 18 | songs_list.insert(END, s) 19 | 20 | def deletesong(): 21 | curr_song=songs_list.curselection() 22 | songs_list.delete(curr_song[0]) 23 | 24 | 25 | def Play(): 26 | song = songs_list.get(ACTIVE) 27 | mixer.music.load(song) 28 | mixer.music.play() 29 | 30 | #to pause the song 31 | def Pause(): 32 | mixer.music.pause() 33 | 34 | #to stop the song 35 | def Stop(): 36 | mixer.music.stop() 37 | songs_list.selection_clear(ACTIVE) 38 | 39 | #to resume the song 40 | 41 | def Resume(): 42 | mixer.music.unpause() 43 | 44 | #Function to navigate from the current song 45 | def Previous(): 46 | # Get the selected song index 47 | previous_one = songs_list.curselection() 48 | if not previous_one: 49 | return 50 | # Get the previous song index 51 | previous_one = previous_one[0] - 1 52 | if previous_one < 0: 53 | previous_one = songs_list.size() - 1 54 | # Get the previous song 55 | temp2 = songs_list.get(previous_one) 56 | mixer.music.load(temp2) 57 | mixer.music.play() 58 | songs_list.selection_clear(0, END) 59 | # Activate new song 60 | songs_list.activate(previous_one) 61 | # Set the next song 62 | songs_list.selection_set(previous_one) 63 | 64 | def Next(): 65 | # Get the selected song index 66 | next_one = songs_list.curselection() 67 | if not next_one: 68 | return 69 | # Get the next song index 70 | next_one = next_one[0] + 1 71 | if next_one >= songs_list.size(): 72 | next_one = 0 73 | # Get the next song 74 | temp = songs_list.get(next_one) 75 | mixer.music.load(temp) 76 | mixer.music.play() 77 | songs_list.selection_clear(0, END) 78 | # Activate new song 79 | songs_list.activate(next_one) 80 | # Set the next song 81 | songs_list.selection_set(next_one) 82 | 83 | 84 | #font is defined which is to be used for the button font 85 | defined_font = font.Font(family='Helvetica') 86 | 87 | #play button 88 | play_button=Button(root,text="Play",width =7,command=Play) 89 | play_button['font']=defined_font 90 | play_button.grid(row=1,column=0) 91 | 92 | #pause button 93 | pause_button=Button(root,text="Pause",width =7,command=Pause) 94 | pause_button['font']=defined_font 95 | pause_button.grid(row=1,column=1) 96 | 97 | #stop button 98 | stop_button=Button(root,text="Stop",width =7,command=Stop) 99 | stop_button['font']=defined_font 100 | stop_button.grid(row=1,column=2) 101 | 102 | #resume button 103 | Resume_button=Button(root,text="Resume",width =7,command=Resume) 104 | Resume_button['font']=defined_font 105 | Resume_button.grid(row=1,column=3) 106 | 107 | #previous button 108 | previous_button=Button(root,text="Prev",width =7,command=Previous) 109 | previous_button['font']=defined_font 110 | previous_button.grid(row=1,column=4) 111 | 112 | #nextbutton 113 | next_button=Button(root,text="Next",width =7,command=Next) 114 | next_button['font']=defined_font 115 | next_button.grid(row=1,column=5) 116 | 117 | #menu 118 | my_menu=Menu(root) 119 | root.config(menu=my_menu) 120 | add_song_menu=Menu(my_menu) 121 | my_menu.add_cascade(label="Menu",menu=add_song_menu) 122 | add_song_menu.add_command(label="Add songs",command=addsongs) 123 | add_song_menu.add_command(label="Delete song",command=deletesong) 124 | 125 | 126 | mainloop() 127 | -------------------------------------------------------------------------------- /file-organizer/README.md: -------------------------------------------------------------------------------- 1 | # File Organizer 📁 2 | 3 | Automatically organize your messy downloads folder by categorizing files into neat folders. 4 | 5 | ## Features 6 | - 🗂️ **Auto-Categorization** - Organizes files into 12+ categories 7 | - 👀 **Dry Run Mode** - Preview changes before organizing 8 | - ↩️ **Undo Function** - Reverse last organization 9 | - 📊 **Statistics** - View file distribution and sizes 10 | - 🧹 **Clean Empty Folders** - Remove unused category folders 11 | - 📝 **Detailed Logging** - Track all operations 12 | - 🎯 **Custom Directory** - Organize any folder, not just Downloads 13 | - 🔄 **Smart Duplicate Handling** - Prevents file overwriting 14 | 15 | ## File Categories 16 | 17 | The organizer sorts files into these categories: 18 | 19 | | Category | File Types | 20 | |----------|------------| 21 | | **Images** | .jpg, .png, .gif, .bmp, .svg, .webp, etc. | 22 | | **Videos** | .mp4, .avi, .mkv, .mov, .wmv, etc. | 23 | | **Audio** | .mp3, .wav, .flac, .aac, .ogg, etc. | 24 | | **Documents** | .pdf, .doc, .docx, .txt, .rtf, etc. | 25 | | **Spreadsheets** | .xls, .xlsx, .csv, .ods | 26 | | **Presentations** | .ppt, .pptx, .odp | 27 | | **Archives** | .zip, .rar, .7z, .tar, .gz | 28 | | **Code** | .py, .java, .js, .html, .css, etc. | 29 | | **Executables** | .exe, .msi, .dmg, .app | 30 | | **Books** | .epub, .mobi, .azw | 31 | | **Design** | .psd, .ai, .sketch, .xd, .fig | 32 | | **Data** | .json, .xml, .yaml, .sql, .db | 33 | 34 | Files not matching any category go to **Others** folder. 35 | 36 | ## Requirements 37 | ```bash 38 | # No external packages required - uses built-in Python libraries 39 | ``` 40 | 41 | ## Usage 42 | ```bash 43 | python file_organizer.py 44 | ``` 45 | 46 | ## Menu Options 47 | 48 | ### 1. Organize Files 49 | Automatically sorts all files in the target directory into categorized folders. 50 | 51 | ### 2. Preview Organization (Dry Run) 52 | Shows what would happen without actually moving files. Perfect for testing! 53 | 54 | ### 3. Undo Last Organization 55 | Restores files to their original locations before the last organization. 56 | 57 | ### 4. Show Statistics 58 | Displays: 59 | - Number of files per category 60 | - Total file count 61 | - Total directory size 62 | 63 | ### 5. Clean Empty Folders 64 | Removes empty category folders to keep directory clean. 65 | 66 | ### 6. Change Target Directory 67 | Organize any folder, not just Downloads. 68 | 69 | ## How It Works 70 | 71 | **Before:** 72 | ``` 73 | Downloads/ 74 | ├── vacation.jpg 75 | ├── report.pdf 76 | ├── song.mp3 77 | ├── video.mp4 78 | └── archive.zip 79 | ``` 80 | 81 | **After:** 82 | ``` 83 | Downloads/ 84 | ├── Images/ 85 | │ └── vacation.jpg 86 | ├── Documents/ 87 | │ └── report.pdf 88 | ├── Audio/ 89 | │ └── song.mp3 90 | ├── Videos/ 91 | │ └── video.mp4 92 | └── Archives/ 93 | └── archive.zip 94 | ``` 95 | 96 | ## Example Session 97 | ``` 98 | 📁 FILE ORGANIZER 📁 99 | 100 | Current directory: /home/user/Downloads 101 | 102 | 1. Organize Files 103 | 2. Preview Organization (Dry Run) 104 | 105 | Enter your choice: 2 106 | 107 | [PREVIEW] vacation.jpg → Images/ 108 | [PREVIEW] report.pdf → Documents/ 109 | [PREVIEW] song.mp3 → Audio/ 110 | 111 | SUMMARY 112 | Images: 1 file(s) 113 | Documents: 1 file(s) 114 | Audio: 1 file(s) 115 | 116 | Total files previewed: 3 117 | ``` 118 | 119 | ## Safety Features 120 | - ✅ **Dry run mode** to preview changes 121 | - ✅ **Undo functionality** to reverse changes 122 | - ✅ **Duplicate handling** - never overwrites files 123 | - ✅ **Detailed logging** of all operations 124 | - ✅ **Skips system/hidden files** 125 | 126 | ## Files Created 127 | - `organization_history.json` - History for undo function 128 | - `file_organizer.log` - Detailed operation logs 129 | 130 | ## Tips 131 | - 💡 Always run **dry run** first to preview changes 132 | - 🔄 Use **undo** if you're not happy with results 133 | - 📊 Check **statistics** regularly to see file distribution 134 | - 🧹 Run **clean empty folders** to maintain tidiness 135 | - 💾 Backup important files before organizing 136 | 137 | ## Customization 138 | You can easily add custom categories by editing the `file_categories` dictionary in the code. 139 | 140 | ## Use Cases 141 | - 🗂️ Organize messy Downloads folder 142 | - 📚 Sort project files 143 | - 🎨 Organize design assets 144 | - 💼 Manage work documents 145 | - 🎵 Sort media collections 146 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🐍 Python Mini Projects Collection 2 | 3 | A collection of beginner-friendly to intermediate Python projects organized in separate folders. Each project is self-contained with its own code and documentation. 4 | 5 | ## 📁 Projects List 6 | 7 | ### 🔐 Security & Utilities 8 | - **[password-manager/](password-manager/)** - Secure password manager with encryption 9 | - **[chatbot/](chatbot/)** - AI chatbot using OpenAI's GPT-3.5 Turbo 10 | - **[qr-code-generator/](qr-code-generator/)** - Generate QR codes from text/URLs 11 | 12 | ### 💰 Finance & Productivity 13 | - **[expense-tracker/](expense-tracker/)** - Track daily expenses with charts and reports 14 | - **[pomodoro-timer/](pomodoro-timer/)** - Productivity timer based on Pomodoro Technique 15 | - **[file-organizer/](file-organizer/)** - Auto-organize files into categorized folders 16 | - **[currency-converter/](currency-converter/)** - Real-time currency converter with 150+ currencies 17 | 18 | ### 🌐 Web & API Projects 19 | - **[weather-detection/](weather-detection/)** - Real-time weather information with GUI 20 | - **[internet-speed-test/](internet-speed-test/)** - Test your internet connection speed 21 | - **[language-translator/](language-translator/)** - Translate text between languages 22 | 23 | ### 🎮 Games & Entertainment 24 | - **[rock-paper-scissors/](rock-paper-scissors/)** - Classic game against computer 25 | - **[tic-tac-toe/](tic-tac-toe/)** - Tic-tac-toe with GUI 26 | - **[mini-games/](mini-games/)** - Blackjack and Caesar Cipher games 27 | 28 | ### 📝 Productivity Tools 29 | - **[text-editor/](text-editor/)** - Simple text editor with save functionality 30 | - **[typing-speed-test/](typing-speed-test/)** - Test your typing speed and accuracy 31 | - **[youtube-video-manager/](youtube-video-manager/)** - Manage YouTube video lists 32 | - **[time-greeting/](time-greeting/)** - Time-based greeting system 33 | 34 | ### 🎵 Media 35 | - **[music-player/](music-player/)** - GUI-based MP3 music player 36 | - **[morse-code-translator/](morse-code-translator/)** - Encode/decode Morse code 37 | 38 | ## 🚀 Getting Started 39 | 40 | ### Installation 41 | 42 | 1. **Clone the repository:** 43 | ```bash 44 | git clone https://github.com/Chiragj2003/mini-projects-.git 45 | cd mini-projects- 46 | ``` 47 | 48 | 2. **Install all dependencies:** 49 | ```bash 50 | pip install -r requirements.txt 51 | ``` 52 | 53 | Or install individual project requirements as needed. 54 | 55 | ### Running a Project 56 | 57 | Each project has its own folder with: 58 | - Python script(s) 59 | - README.md with specific instructions 60 | - Project-specific requirements 61 | 62 | Navigate to any project folder and run: 63 | ```bash 64 | cd project-name/ 65 | python project_file.py 66 | ``` 67 | 68 | ## 📦 Installation 69 | 70 | ### Install All Dependencies 71 | ```bash 72 | pip install -r requirements.txt 73 | ``` 74 | 75 | ### Individual Package Installation 76 | Some projects may require specific packages: 77 | ```bash 78 | # Password Manager 79 | pip install cryptography 80 | 81 | # Expense Tracker 82 | pip install matplotlib 83 | 84 | # Currency Converter & Weather Detection 85 | pip install requests 86 | 87 | # Chatbot 88 | pip install openai 89 | 90 | # QR Code Generator 91 | pip install qrcode pillow 92 | 93 | # Music Player 94 | pip install pygame 95 | 96 | # Language Translator 97 | pip install translate 98 | 99 | # Internet Speed Test 100 | pip install speedtest-cli 101 | ``` 102 | 103 | **Note:** Tkinter comes pre-installed with Python. Many projects use only built-in libraries. 104 | 105 | --- 106 | 107 | ## 📖 Featured Projects 108 | 109 | ### 🔐 Password Manager 110 | Secure command-line password manager with military-grade encryption. Store, retrieve, and manage passwords safely with master password protection. 111 | 112 | ### 💰 Expense Tracker 113 | Track your daily expenses with detailed reports and beautiful visualizations. Features monthly summaries, category-based filtering, and multiple chart types for analyzing spending patterns. 114 | 115 | ### 🍅 Pomodoro Timer 116 | Beautiful productivity timer with GUI based on the Pomodoro Technique. Features 25-minute work sessions, automatic breaks, sound notifications, and daily statistics tracking. 117 | 118 | ### 📁 File Organizer 119 | Automatically organize messy folders by categorizing files into 12+ predefined categories. Features dry run mode, undo functionality, statistics, and detailed logging. 120 | 121 | ### 💱 Currency Converter 122 | Real-time currency converter with beautiful GUI supporting 150+ world currencies. Features smart caching, conversion history, offline mode, and quick access to popular currency rates. 123 | 124 | --- 125 | 126 | ## 📊 Project Statistics 127 | 128 | - **Total Projects:** 20 129 | - **Categories:** 6 130 | - **Languages:** Python 131 | - **Total Lines of Code:** 5000+ 132 | - **Difficulty:** Beginner to Intermediate 133 | 134 | ## 🤝 Contributing 135 | 136 | Contributions are welcome! Feel free to: 137 | - 🐛 Report bugs 138 | - 💡 Suggest new project ideas 139 | - 🔧 Submit pull requests 140 | - 📝 Improve documentation 141 | 142 | ## 📜 License 143 | 144 | This project is open source and available for educational purposes. 145 | 146 | ## 👨‍💻 Author 147 | 148 | **Chirag J** 149 | - GitHub: [@Chiragj2003](https://github.com/Chiragj2003) 150 | 151 | ## ⭐ Show Your Support 152 | 153 | Give a ⭐️ if you found these projects helpful! 154 | 155 | --- 156 | 157 | ## 📚 Additional Documentation 158 | 159 | # Speed Test Code 160 | Imagine a program that lets you test your internet speed with just a click 161 | ! This Python script builds a basic screen with a "Start Test" button. Once 162 | you click it, the program uses a tool called "speedtest" to measure how fast your 163 | internet uploads and downloads data, and how long it takes to connect to websites. 164 | It then displays the results on the screen, showing you download speed (for things like streaming videos) 165 | , upload speed (for sending emails or photos), and even the 166 | response time (how long it takes to talk to websites). It's like having a mini 167 | internet speedometer for your computer! 168 | While this program works well, it can be improved by removing unnecessary 169 | windows and organizing the code more neatly. But overall, it's a cool example of using Python to create a simple and helpful tool! 170 | 171 | # Typing speed and accuracy test 172 | This Python script conducts a typing speed and accuracy test. It randomly selects a sentence from a predefined list, prompts the user to type it, measures the time taken, and calculates typing speed and accuracy. The program showcases random sentence generation, input handling, and basic performance metrics. Users receive feedback on their typing speed, accuracy, and overall performance after completing the test. 173 | 174 | 175 | # Language Translation Using Tkinter 176 | 177 | This Python script implements a simple language translation application using Tkinter and the `translate` library. The application provides a user-friendly interface for translating text from one language to another. 178 | 179 | # youtube video manager 180 | This Python script manages YouTube videos with functionalities to list, add, update, and delete videos stored in a JSON file. It provides a text-based menu for user interaction, allowing seamless video management and updates while maintaining data integrity by saving changes to the file. 181 | 182 | ## Features 183 | - **Language Selection:** Users can choose both the input language and the target language from a list of available options, including Hindi, English, French, German, and Spanish. 184 | - **Text Input and Output:** Enter the text to be translated in the "Enter Text" field, and the translated output will be displayed in the "Output Text" field. Tkinter StringVar variables are used to dynamically link input and output fields. 185 | - **Translation Functionality:** The translation is performed using the `translate` function from the `translate` library. The translation function is triggered when the user clicks the "Translate" button. 186 | - **Graphical User Interface:** The Tkinter library is utilized to create a basic graphical user interface with labels, entry fields, drop-down menus, and a translation button. 187 | 188 | ## Dependencies 189 | 190 | - Tkinter 191 | - `translate` 192 | 193 | ## Further Customization 194 | 195 | Feel free to customize the code or expand the application by adding more features, error handling, or enhancing the user interface. 196 | 197 | ## Conclusion 198 | 199 | This language translation application serves as a practical example for beginners interested in building graphical applications for language processing tasks. Explore the code, experiment with different languages, and adapt it to your specific needs. 200 | 201 | 202 | -------------------------------------------------------------------------------- /password-manager/password_manager.py: -------------------------------------------------------------------------------- 1 | """ 2 | Password Manager - Store encrypted passwords securely 3 | Features: 4 | - Add new passwords with encryption 5 | - View stored passwords (decrypted) 6 | - Search for passwords by account name 7 | - Delete passwords 8 | - Master password protection 9 | - Data stored in encrypted format 10 | """ 11 | 12 | import json 13 | import os 14 | from cryptography.fernet import Fernet 15 | import getpass 16 | import hashlib 17 | from pathlib import Path 18 | 19 | class PasswordManager: 20 | def __init__(self): 21 | self.data_file = "passwords.json" 22 | self.key_file = "key.key" 23 | self.master_hash_file = "master.hash" 24 | self.cipher = None 25 | 26 | def generate_key(self): 27 | """Generate encryption key""" 28 | key = Fernet.generate_key() 29 | with open(self.key_file, 'wb') as key_file: 30 | key_file.write(key) 31 | return key 32 | 33 | def load_key(self): 34 | """Load encryption key""" 35 | if not os.path.exists(self.key_file): 36 | return self.generate_key() 37 | with open(self.key_file, 'rb') as key_file: 38 | return key_file.read() 39 | 40 | def hash_master_password(self, password): 41 | """Hash the master password""" 42 | return hashlib.sha256(password.encode()).hexdigest() 43 | 44 | def setup_master_password(self): 45 | """Setup master password for first time""" 46 | print("\n=== First Time Setup ===") 47 | while True: 48 | master_pass = getpass.getpass("Create a master password: ") 49 | confirm_pass = getpass.getpass("Confirm master password: ") 50 | 51 | if master_pass == confirm_pass: 52 | hashed = self.hash_master_password(master_pass) 53 | with open(self.master_hash_file, 'w') as f: 54 | f.write(hashed) 55 | print("✓ Master password set successfully!") 56 | return True 57 | else: 58 | print("✗ Passwords don't match. Try again.") 59 | 60 | def verify_master_password(self): 61 | """Verify master password""" 62 | if not os.path.exists(self.master_hash_file): 63 | return self.setup_master_password() 64 | 65 | with open(self.master_hash_file, 'r') as f: 66 | stored_hash = f.read() 67 | 68 | attempts = 3 69 | while attempts > 0: 70 | master_pass = getpass.getpass("\nEnter master password: ") 71 | if self.hash_master_password(master_pass) == stored_hash: 72 | print("✓ Access granted!") 73 | return True 74 | else: 75 | attempts -= 1 76 | if attempts > 0: 77 | print(f"✗ Incorrect password. {attempts} attempts remaining.") 78 | else: 79 | print("✗ Too many failed attempts. Exiting.") 80 | return False 81 | return False 82 | 83 | def encrypt_password(self, password): 84 | """Encrypt a password""" 85 | return self.cipher.encrypt(password.encode()).decode() 86 | 87 | def decrypt_password(self, encrypted_password): 88 | """Decrypt a password""" 89 | return self.cipher.decrypt(encrypted_password.encode()).decode() 90 | 91 | def load_passwords(self): 92 | """Load passwords from file""" 93 | if not os.path.exists(self.data_file): 94 | return {} 95 | try: 96 | with open(self.data_file, 'r') as f: 97 | return json.load(f) 98 | except json.JSONDecodeError: 99 | return {} 100 | 101 | def save_passwords(self, passwords): 102 | """Save passwords to file""" 103 | with open(self.data_file, 'w') as f: 104 | json.dump(passwords, f, indent=4) 105 | 106 | def add_password(self): 107 | """Add a new password""" 108 | print("\n=== Add New Password ===") 109 | account = input("Account/Website name: ").strip() 110 | username = input("Username/Email: ").strip() 111 | password = getpass.getpass("Password: ") 112 | 113 | passwords = self.load_passwords() 114 | 115 | if account in passwords: 116 | overwrite = input(f"Account '{account}' already exists. Overwrite? (y/n): ") 117 | if overwrite.lower() != 'y': 118 | print("✗ Cancelled.") 119 | return 120 | 121 | passwords[account] = { 122 | 'username': username, 123 | 'password': self.encrypt_password(password) 124 | } 125 | 126 | self.save_passwords(passwords) 127 | print(f"✓ Password for '{account}' saved successfully!") 128 | 129 | def view_passwords(self): 130 | """View all stored passwords""" 131 | passwords = self.load_passwords() 132 | 133 | if not passwords: 134 | print("\n✗ No passwords stored yet.") 135 | return 136 | 137 | print("\n" + "="*70) 138 | print("STORED PASSWORDS".center(70)) 139 | print("="*70) 140 | 141 | for account, data in passwords.items(): 142 | decrypted_pass = self.decrypt_password(data['password']) 143 | print(f"\n🔐 Account: {account}") 144 | print(f" Username: {data['username']}") 145 | print(f" Password: {decrypted_pass}") 146 | 147 | print("\n" + "="*70) 148 | 149 | def search_password(self): 150 | """Search for a specific password""" 151 | print("\n=== Search Password ===") 152 | search_term = input("Enter account name: ").strip() 153 | 154 | passwords = self.load_passwords() 155 | 156 | # Case-insensitive search 157 | found = False 158 | for account, data in passwords.items(): 159 | if search_term.lower() in account.lower(): 160 | decrypted_pass = self.decrypt_password(data['password']) 161 | print(f"\n🔐 Account: {account}") 162 | print(f" Username: {data['username']}") 163 | print(f" Password: {decrypted_pass}") 164 | found = True 165 | 166 | if not found: 167 | print(f"✗ No account found matching '{search_term}'") 168 | 169 | def delete_password(self): 170 | """Delete a password""" 171 | print("\n=== Delete Password ===") 172 | passwords = self.load_passwords() 173 | 174 | if not passwords: 175 | print("✗ No passwords stored.") 176 | return 177 | 178 | print("\nStored accounts:") 179 | for idx, account in enumerate(passwords.keys(), 1): 180 | print(f"{idx}. {account}") 181 | 182 | account = input("\nEnter account name to delete: ").strip() 183 | 184 | if account in passwords: 185 | confirm = input(f"Are you sure you want to delete '{account}'? (y/n): ") 186 | if confirm.lower() == 'y': 187 | del passwords[account] 188 | self.save_passwords(passwords) 189 | print(f"✓ Password for '{account}' deleted successfully!") 190 | else: 191 | print("✗ Cancelled.") 192 | else: 193 | print(f"✗ Account '{account}' not found.") 194 | 195 | def show_menu(self): 196 | """Display main menu""" 197 | print("\n" + "="*50) 198 | print("PASSWORD MANAGER".center(50)) 199 | print("="*50) 200 | print("1. Add New Password") 201 | print("2. View All Passwords") 202 | print("3. Search Password") 203 | print("4. Delete Password") 204 | print("5. Exit") 205 | print("="*50) 206 | 207 | def run(self): 208 | """Main program loop""" 209 | print("="*50) 210 | print("🔐 SECURE PASSWORD MANAGER 🔐".center(50)) 211 | print("="*50) 212 | 213 | # Verify master password 214 | if not self.verify_master_password(): 215 | return 216 | 217 | # Load encryption key 218 | key = self.load_key() 219 | self.cipher = Fernet(key) 220 | 221 | while True: 222 | self.show_menu() 223 | choice = input("\nEnter your choice (1-5): ").strip() 224 | 225 | if choice == '1': 226 | self.add_password() 227 | elif choice == '2': 228 | self.view_passwords() 229 | elif choice == '3': 230 | self.search_password() 231 | elif choice == '4': 232 | self.delete_password() 233 | elif choice == '5': 234 | print("\n👋 Goodbye! Your passwords are secure.") 235 | break 236 | else: 237 | print("✗ Invalid choice. Please try again.") 238 | 239 | if __name__ == "__main__": 240 | manager = PasswordManager() 241 | manager.run() 242 | -------------------------------------------------------------------------------- /tic-tac-toe/tic_tac_toe.py: -------------------------------------------------------------------------------- 1 | from tkinter import * 2 | 3 | import numpy as np 4 | 5 | 6 | 7 | size_of_board = 600 8 | 9 | symbol_size = (size_of_board / 3 - size_of_board / 8) / 2 10 | 11 | symbol_thickness = 50 12 | 13 | symbol_X_color = '#EE4035' 14 | 15 | symbol_O_color = '#0492CF' 16 | 17 | Green_color = '#7BC043' 18 | 19 | 20 | 21 | 22 | 23 | class Tic_Tac_Toe(): 24 | 25 | # ------------------------------------------------------------------ 26 | 27 | # Initialization Functions: 28 | 29 | # ------------------------------------------------------------------ 30 | 31 | def __init__(self): 32 | 33 | self.window = Tk() 34 | 35 | self.window.title('Tic-Tac-Toe') 36 | 37 | self.canvas = Canvas(self.window, width=size_of_board, height=size_of_board) 38 | 39 | self.canvas.pack() 40 | 41 | # Input from user in form of clicks 42 | 43 | self.window.bind('', self.click) 44 | 45 | 46 | 47 | self.initialize_board() 48 | 49 | self.player_X_turns = True 50 | 51 | self.board_status = np.zeros(shape=(3, 3)) 52 | 53 | 54 | 55 | self.player_X_starts = True 56 | 57 | self.reset_board = False 58 | 59 | self.gameover = False 60 | 61 | self.tie = False 62 | 63 | self.X_wins = False 64 | 65 | self.O_wins = False 66 | 67 | 68 | 69 | self.X_score = 0 70 | 71 | self.O_score = 0 72 | 73 | self.tie_score = 0 74 | 75 | 76 | 77 | def mainloop(self): 78 | 79 | self.window.mainloop() 80 | 81 | 82 | 83 | def initialize_board(self): 84 | 85 | for i in range(2): 86 | 87 | self.canvas.create_line((i + 1) * size_of_board / 3, 0, (i + 1) * size_of_board / 3, size_of_board) 88 | 89 | 90 | 91 | for i in range(2): 92 | 93 | self.canvas.create_line(0, (i + 1) * size_of_board / 3, size_of_board, (i + 1) * size_of_board / 3) 94 | 95 | 96 | 97 | def play_again(self): 98 | 99 | self.initialize_board() 100 | 101 | self.player_X_starts = not self.player_X_starts 102 | 103 | self.player_X_turns = self.player_X_starts 104 | 105 | self.board_status = np.zeros(shape=(3, 3)) 106 | 107 | 108 | 109 | # ------------------------------------------------------------------ 110 | 111 | # Drawing Functions: 112 | 113 | # The modules required to draw required game based object on canvas 114 | 115 | # ------------------------------------------------------------------ 116 | 117 | 118 | 119 | def draw_O(self, logical_position): 120 | 121 | logical_position = np.array(logical_position) 122 | 123 | # logical_position = grid value on the board 124 | 125 | # grid_position = actual pixel values of the center of the grid 126 | 127 | grid_position = self.convert_logical_to_grid_position(logical_position) 128 | 129 | self.canvas.create_oval(grid_position[0] - symbol_size, grid_position[1] - symbol_size, 130 | 131 | grid_position[0] + symbol_size, grid_position[1] + symbol_size, width=symbol_thickness, 132 | 133 | outline=symbol_O_color) 134 | 135 | 136 | 137 | def draw_X(self, logical_position): 138 | 139 | grid_position = self.convert_logical_to_grid_position(logical_position) 140 | 141 | self.canvas.create_line(grid_position[0] - symbol_size, grid_position[1] - symbol_size, 142 | 143 | grid_position[0] + symbol_size, grid_position[1] + symbol_size, width=symbol_thickness, 144 | 145 | fill=symbol_X_color) 146 | 147 | self.canvas.create_line(grid_position[0] - symbol_size, grid_position[1] + symbol_size, 148 | 149 | grid_position[0] + symbol_size, grid_position[1] - symbol_size, width=symbol_thickness, 150 | 151 | fill=symbol_X_color) 152 | 153 | 154 | 155 | def display_gameover(self): 156 | 157 | 158 | 159 | if self.X_wins: 160 | 161 | self.X_score += 1 162 | 163 | text = 'Winner: Player 1 (X)' 164 | 165 | color = symbol_X_color 166 | 167 | elif self.O_wins: 168 | 169 | self.O_score += 1 170 | 171 | text = 'Winner: Player 2 (O)' 172 | 173 | color = symbol_O_color 174 | 175 | else: 176 | 177 | self.tie_score += 1 178 | 179 | text = 'Its a tie' 180 | 181 | color = 'gray' 182 | 183 | 184 | 185 | self.canvas.delete("all") 186 | 187 | self.canvas.create_text(size_of_board / 2, size_of_board / 3, font="cmr 60 bold", fill=color, text=text) 188 | 189 | 190 | 191 | score_text = 'Scores \n' 192 | 193 | self.canvas.create_text(size_of_board / 2, 5 * size_of_board / 8, font="cmr 40 bold", fill=Green_color, 194 | 195 | text=score_text) 196 | 197 | 198 | 199 | score_text = 'Player 1 (X) : ' + str(self.X_score) + '\n' 200 | 201 | score_text += 'Player 2 (O): ' + str(self.O_score) + '\n' 202 | 203 | score_text += 'Tie : ' + str(self.tie_score) 204 | 205 | self.canvas.create_text(size_of_board / 2, 3 * size_of_board / 4, font="cmr 30 bold", fill=Green_color, 206 | 207 | text=score_text) 208 | 209 | self.reset_board = True 210 | 211 | 212 | 213 | score_text = 'Click to play again \n' 214 | 215 | self.canvas.create_text(size_of_board / 2, 15 * size_of_board / 16, font="cmr 20 bold", fill="gray", 216 | 217 | text=score_text) 218 | 219 | 220 | 221 | # ------------------------------------------------------------------ 222 | 223 | # Logical Functions: 224 | 225 | # The modules required to carry out game logic 226 | 227 | # ------------------------------------------------------------------ 228 | 229 | 230 | 231 | def convert_logical_to_grid_position(self, logical_position): 232 | 233 | logical_position = np.array(logical_position, dtype=int) 234 | 235 | return (size_of_board / 3) * logical_position + size_of_board / 6 236 | 237 | 238 | 239 | def convert_grid_to_logical_position(self, grid_position): 240 | 241 | grid_position = np.array(grid_position) 242 | 243 | return np.array(grid_position // (size_of_board / 3), dtype=int) 244 | 245 | 246 | 247 | def is_grid_occupied(self, logical_position): 248 | 249 | if self.board_status[logical_position[0]][logical_position[1]] == 0: 250 | 251 | return False 252 | 253 | else: 254 | 255 | return True 256 | 257 | 258 | 259 | def is_winner(self, player): 260 | 261 | 262 | 263 | player = -1 if player == 'X' else 1 264 | 265 | 266 | 267 | # Three in a row 268 | 269 | for i in range(3): 270 | 271 | if self.board_status[i][0] == self.board_status[i][1] == self.board_status[i][2] == player: 272 | 273 | return True 274 | 275 | if self.board_status[0][i] == self.board_status[1][i] == self.board_status[2][i] == player: 276 | 277 | return True 278 | 279 | 280 | 281 | # Diagonals 282 | 283 | if self.board_status[0][0] == self.board_status[1][1] == self.board_status[2][2] == player: 284 | 285 | return True 286 | 287 | 288 | 289 | if self.board_status[0][2] == self.board_status[1][1] == self.board_status[2][0] == player: 290 | 291 | return True 292 | 293 | 294 | 295 | return False 296 | 297 | 298 | 299 | def is_tie(self): 300 | 301 | 302 | 303 | r, c = np.where(self.board_status == 0) 304 | 305 | tie = False 306 | 307 | if len(r) == 0: 308 | 309 | tie = True 310 | 311 | 312 | 313 | return tie 314 | 315 | 316 | 317 | def is_gameover(self): 318 | 319 | # Either someone wins or all grid occupied 320 | 321 | self.X_wins = self.is_winner('X') 322 | 323 | if not self.X_wins: 324 | 325 | self.O_wins = self.is_winner('O') 326 | 327 | 328 | 329 | if not self.O_wins: 330 | 331 | self.tie = self.is_tie() 332 | 333 | 334 | 335 | gameover = self.X_wins or self.O_wins or self.tie 336 | 337 | 338 | 339 | if self.X_wins: 340 | 341 | print('X wins') 342 | 343 | if self.O_wins: 344 | 345 | print('O wins') 346 | 347 | if self.tie: 348 | 349 | print('Its a tie') 350 | 351 | 352 | 353 | return gameover 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | def click(self, event): 366 | 367 | grid_position = [event.x, event.y] 368 | 369 | logical_position = self.convert_grid_to_logical_position(grid_position) 370 | 371 | 372 | 373 | if not self.reset_board: 374 | 375 | if self.player_X_turns: 376 | 377 | if not self.is_grid_occupied(logical_position): 378 | 379 | self.draw_X(logical_position) 380 | 381 | self.board_status[logical_position[0]][logical_position[1]] = -1 382 | 383 | self.player_X_turns = not self.player_X_turns 384 | 385 | else: 386 | 387 | if not self.is_grid_occupied(logical_position): 388 | 389 | self.draw_O(logical_position) 390 | 391 | self.board_status[logical_position[0]][logical_position[1]] = 1 392 | 393 | self.player_X_turns = not self.player_X_turns 394 | 395 | 396 | 397 | # Check if game is concluded 398 | 399 | if self.is_gameover(): 400 | 401 | self.display_gameover() 402 | 403 | # print('Done') 404 | 405 | else: # Play Again 406 | 407 | self.canvas.delete("all") 408 | 409 | self.play_again() 410 | 411 | self.reset_board = False 412 | 413 | 414 | 415 | 416 | 417 | game_instance = Tic_Tac_Toe() 418 | 419 | game_instance.mainloop() -------------------------------------------------------------------------------- /pomodoro-timer/pomodoro_timer.py: -------------------------------------------------------------------------------- 1 | """ 2 | Pomodoro Timer - Productivity timer with breaks 3 | Features: 4 | - 25-minute work sessions 5 | - 5-minute short breaks 6 | - 15-minute long breaks after 4 sessions 7 | - Visual countdown timer 8 | - Sound notifications 9 | - Session tracking 10 | - Statistics and productivity reports 11 | """ 12 | 13 | import tkinter as tk 14 | from tkinter import ttk, messagebox 15 | import time 16 | from datetime import datetime 17 | import json 18 | import os 19 | 20 | try: 21 | import winsound 22 | SOUND_AVAILABLE = True 23 | except ImportError: 24 | SOUND_AVAILABLE = False 25 | 26 | class PomodoroTimer: 27 | def __init__(self, root): 28 | self.root = root 29 | self.root.title("🍅 Pomodoro Timer") 30 | self.root.geometry("500x650") 31 | self.root.resizable(False, False) 32 | self.root.configure(bg='#2C3E50') 33 | 34 | # Timer settings (in seconds) 35 | self.WORK_TIME = 25 * 60 # 25 minutes 36 | self.SHORT_BREAK = 5 * 60 # 5 minutes 37 | self.LONG_BREAK = 15 * 60 # 15 minutes 38 | 39 | # Timer state 40 | self.time_left = self.WORK_TIME 41 | self.is_running = False 42 | self.is_work_session = True 43 | self.sessions_completed = 0 44 | self.timer_id = None 45 | 46 | # Statistics file 47 | self.stats_file = "pomodoro_stats.json" 48 | 49 | # Create UI 50 | self.create_widgets() 51 | self.load_stats() 52 | self.update_display() 53 | 54 | def create_widgets(self): 55 | """Create all UI widgets""" 56 | 57 | # Title 58 | title_label = tk.Label( 59 | self.root, 60 | text="🍅 POMODORO TIMER", 61 | font=('Helvetica', 24, 'bold'), 62 | bg='#2C3E50', 63 | fg='#ECF0F1' 64 | ) 65 | title_label.pack(pady=20) 66 | 67 | # Session info 68 | self.session_label = tk.Label( 69 | self.root, 70 | text="Work Session", 71 | font=('Helvetica', 18), 72 | bg='#2C3E50', 73 | fg='#E74C3C' 74 | ) 75 | self.session_label.pack(pady=10) 76 | 77 | # Timer display 78 | self.timer_frame = tk.Frame(self.root, bg='#34495E', bd=5, relief='ridge') 79 | self.timer_frame.pack(pady=20, padx=50, fill='both', expand=True) 80 | 81 | self.timer_label = tk.Label( 82 | self.timer_frame, 83 | text="25:00", 84 | font=('Courier', 60, 'bold'), 85 | bg='#34495E', 86 | fg='#ECF0F1' 87 | ) 88 | self.timer_label.pack(pady=40) 89 | 90 | # Progress bar 91 | self.progress = ttk.Progressbar( 92 | self.root, 93 | length=400, 94 | mode='determinate', 95 | style='Custom.Horizontal.TProgressbar' 96 | ) 97 | self.progress.pack(pady=10) 98 | 99 | # Buttons frame 100 | button_frame = tk.Frame(self.root, bg='#2C3E50') 101 | button_frame.pack(pady=20) 102 | 103 | # Start/Pause button 104 | self.start_button = tk.Button( 105 | button_frame, 106 | text="▶ START", 107 | command=self.toggle_timer, 108 | font=('Helvetica', 14, 'bold'), 109 | bg='#27AE60', 110 | fg='white', 111 | width=12, 112 | height=2, 113 | relief='raised', 114 | bd=3, 115 | cursor='hand2' 116 | ) 117 | self.start_button.grid(row=0, column=0, padx=10) 118 | 119 | # Reset button 120 | reset_button = tk.Button( 121 | button_frame, 122 | text="⟲ RESET", 123 | command=self.reset_timer, 124 | font=('Helvetica', 14, 'bold'), 125 | bg='#E67E22', 126 | fg='white', 127 | width=12, 128 | height=2, 129 | relief='raised', 130 | bd=3, 131 | cursor='hand2' 132 | ) 133 | reset_button.grid(row=0, column=1, padx=10) 134 | 135 | # Skip button 136 | skip_button = tk.Button( 137 | button_frame, 138 | text="⏭ SKIP", 139 | command=self.skip_session, 140 | font=('Helvetica', 14, 'bold'), 141 | bg='#3498DB', 142 | fg='white', 143 | width=12, 144 | height=2, 145 | relief='raised', 146 | bd=3, 147 | cursor='hand2' 148 | ) 149 | skip_button.grid(row=0, column=2, padx=10) 150 | 151 | # Statistics frame 152 | stats_frame = tk.Frame(self.root, bg='#34495E', bd=3, relief='ridge') 153 | stats_frame.pack(pady=20, padx=50, fill='x') 154 | 155 | stats_title = tk.Label( 156 | stats_frame, 157 | text="📊 Today's Statistics", 158 | font=('Helvetica', 14, 'bold'), 159 | bg='#34495E', 160 | fg='#ECF0F1' 161 | ) 162 | stats_title.pack(pady=5) 163 | 164 | self.stats_label = tk.Label( 165 | stats_frame, 166 | text="Sessions: 0 | Total Time: 0 min", 167 | font=('Helvetica', 12), 168 | bg='#34495E', 169 | fg='#ECF0F1' 170 | ) 171 | self.stats_label.pack(pady=5) 172 | 173 | # Configure progress bar style 174 | style = ttk.Style() 175 | style.theme_use('clam') 176 | style.configure( 177 | 'Custom.Horizontal.TProgressbar', 178 | troughcolor='#34495E', 179 | background='#27AE60', 180 | thickness=20 181 | ) 182 | 183 | def toggle_timer(self): 184 | """Start or pause the timer""" 185 | if self.is_running: 186 | self.pause_timer() 187 | else: 188 | self.start_timer() 189 | 190 | def start_timer(self): 191 | """Start the timer""" 192 | self.is_running = True 193 | self.start_button.config(text="⏸ PAUSE", bg='#E67E22') 194 | self.countdown() 195 | 196 | def pause_timer(self): 197 | """Pause the timer""" 198 | self.is_running = False 199 | self.start_button.config(text="▶ RESUME", bg='#27AE60') 200 | if self.timer_id: 201 | self.root.after_cancel(self.timer_id) 202 | 203 | def countdown(self): 204 | """Countdown timer logic""" 205 | if self.is_running and self.time_left > 0: 206 | self.time_left -= 1 207 | self.update_display() 208 | self.timer_id = self.root.after(1000, self.countdown) 209 | elif self.time_left == 0: 210 | self.session_complete() 211 | 212 | def update_display(self): 213 | """Update timer display and progress bar""" 214 | minutes = self.time_left // 60 215 | seconds = self.time_left % 60 216 | self.timer_label.config(text=f"{minutes:02d}:{seconds:02d}") 217 | 218 | # Update progress bar 219 | if self.is_work_session: 220 | total_time = self.WORK_TIME 221 | elif self.sessions_completed % 4 == 0 and self.sessions_completed > 0: 222 | total_time = self.LONG_BREAK 223 | else: 224 | total_time = self.SHORT_BREAK 225 | 226 | progress_value = ((total_time - self.time_left) / total_time) * 100 227 | self.progress['value'] = progress_value 228 | 229 | def session_complete(self): 230 | """Handle session completion""" 231 | self.is_running = False 232 | self.play_sound() 233 | 234 | if self.is_work_session: 235 | # Work session completed 236 | self.sessions_completed += 1 237 | self.save_session() 238 | self.update_stats_display() 239 | 240 | # Determine break type 241 | if self.sessions_completed % 4 == 0: 242 | # Long break 243 | self.time_left = self.LONG_BREAK 244 | self.session_label.config(text="Long Break", fg='#9B59B6') 245 | messagebox.showinfo( 246 | "Break Time!", 247 | f"Great work! Session {self.sessions_completed} complete!\n" 248 | "Take a 15-minute long break! 🎉" 249 | ) 250 | else: 251 | # Short break 252 | self.time_left = self.SHORT_BREAK 253 | self.session_label.config(text="Short Break", fg='#3498DB') 254 | messagebox.showinfo( 255 | "Break Time!", 256 | f"Session {self.sessions_completed} complete!\n" 257 | "Take a 5-minute break! ☕" 258 | ) 259 | 260 | self.is_work_session = False 261 | else: 262 | # Break completed 263 | self.time_left = self.WORK_TIME 264 | self.session_label.config(text="Work Session", fg='#E74C3C') 265 | self.is_work_session = True 266 | messagebox.showinfo( 267 | "Back to Work!", 268 | "Break is over. Time to focus! 💪" 269 | ) 270 | 271 | self.start_button.config(text="▶ START", bg='#27AE60') 272 | self.update_display() 273 | 274 | def reset_timer(self): 275 | """Reset the timer""" 276 | if self.timer_id: 277 | self.root.after_cancel(self.timer_id) 278 | 279 | self.is_running = False 280 | self.is_work_session = True 281 | self.time_left = self.WORK_TIME 282 | self.session_label.config(text="Work Session", fg='#E74C3C') 283 | self.start_button.config(text="▶ START", bg='#27AE60') 284 | self.progress['value'] = 0 285 | self.update_display() 286 | 287 | def skip_session(self): 288 | """Skip current session""" 289 | if messagebox.askyesno("Skip Session", "Are you sure you want to skip this session?"): 290 | if self.timer_id: 291 | self.root.after_cancel(self.timer_id) 292 | self.time_left = 0 293 | self.session_complete() 294 | 295 | def play_sound(self): 296 | """Play notification sound""" 297 | if SOUND_AVAILABLE: 298 | try: 299 | winsound.Beep(1000, 500) # Frequency: 1000Hz, Duration: 500ms 300 | except: 301 | pass 302 | # Alternative: print('\a') for system beep 303 | print('\a') 304 | 305 | def save_session(self): 306 | """Save completed session to stats""" 307 | stats = self.load_stats() 308 | today = datetime.now().strftime("%Y-%m-%d") 309 | 310 | if today not in stats: 311 | stats[today] = {'sessions': 0, 'total_minutes': 0} 312 | 313 | stats[today]['sessions'] += 1 314 | stats[today]['total_minutes'] += self.WORK_TIME // 60 315 | 316 | with open(self.stats_file, 'w') as f: 317 | json.dump(stats, f, indent=4) 318 | 319 | def load_stats(self): 320 | """Load statistics from file""" 321 | if not os.path.exists(self.stats_file): 322 | return {} 323 | try: 324 | with open(self.stats_file, 'r') as f: 325 | return json.load(f) 326 | except: 327 | return {} 328 | 329 | def update_stats_display(self): 330 | """Update statistics display""" 331 | stats = self.load_stats() 332 | today = datetime.now().strftime("%Y-%m-%d") 333 | 334 | if today in stats: 335 | sessions = stats[today]['sessions'] 336 | total_minutes = stats[today]['total_minutes'] 337 | self.stats_label.config( 338 | text=f"Sessions: {sessions} | Total Time: {total_minutes} min" 339 | ) 340 | else: 341 | self.stats_label.config(text="Sessions: 0 | Total Time: 0 min") 342 | 343 | def run(self): 344 | """Start the application""" 345 | self.root.mainloop() 346 | 347 | if __name__ == "__main__": 348 | root = tk.Tk() 349 | app = PomodoroTimer(root) 350 | app.run() 351 | -------------------------------------------------------------------------------- /file-organizer/file_organizer.py: -------------------------------------------------------------------------------- 1 | """ 2 | File Organizer - Auto-organize downloads folder 3 | Features: 4 | - Organize files by extension into categorized folders 5 | - Move files to appropriate folders (Documents, Images, Videos, etc.) 6 | - Undo last organization 7 | - Dry run mode (preview changes) 8 | - Custom folder mappings 9 | - Schedule automatic organization 10 | - Detailed logging 11 | """ 12 | 13 | import os 14 | import shutil 15 | from pathlib import Path 16 | from datetime import datetime 17 | import json 18 | 19 | class FileOrganizer: 20 | def __init__(self, target_directory=None): 21 | # Set target directory (default: Downloads folder) 22 | if target_directory: 23 | self.target_dir = Path(target_directory) 24 | else: 25 | self.target_dir = Path.home() / "Downloads" 26 | 27 | # File categories 28 | self.file_categories = { 29 | 'Images': ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.svg', '.ico', '.webp', '.tiff'], 30 | 'Videos': ['.mp4', '.avi', '.mkv', '.mov', '.wmv', '.flv', '.webm', '.m4v'], 31 | 'Audio': ['.mp3', '.wav', '.flac', '.aac', '.ogg', '.wma', '.m4a'], 32 | 'Documents': ['.pdf', '.doc', '.docx', '.txt', '.rtf', '.odt', '.tex'], 33 | 'Spreadsheets': ['.xls', '.xlsx', '.csv', '.ods'], 34 | 'Presentations': ['.ppt', '.pptx', '.odp'], 35 | 'Archives': ['.zip', '.rar', '.7z', '.tar', '.gz', '.bz2'], 36 | 'Code': ['.py', '.java', '.cpp', '.c', '.js', '.html', '.css', '.php', '.rb', '.go', '.rs'], 37 | 'Executables': ['.exe', '.msi', '.dmg', '.app', '.deb', '.rpm'], 38 | 'Books': ['.epub', '.mobi', '.azw', '.azw3'], 39 | 'Design': ['.psd', '.ai', '.sketch', '.xd', '.fig'], 40 | 'Data': ['.json', '.xml', '.yaml', '.yml', '.sql', '.db', '.sqlite'] 41 | } 42 | 43 | # History file for undo functionality 44 | self.history_file = "organization_history.json" 45 | self.log_file = "file_organizer.log" 46 | 47 | def log(self, message): 48 | """Log message to file and console""" 49 | timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") 50 | log_message = f"[{timestamp}] {message}" 51 | print(log_message) 52 | 53 | with open(self.log_file, 'a', encoding='utf-8') as f: 54 | f.write(log_message + '\n') 55 | 56 | def get_file_category(self, file_path): 57 | """Determine file category based on extension""" 58 | extension = file_path.suffix.lower() 59 | 60 | for category, extensions in self.file_categories.items(): 61 | if extension in extensions: 62 | return category 63 | 64 | return 'Others' 65 | 66 | def organize_files(self, dry_run=False): 67 | """Organize files in target directory""" 68 | if not self.target_dir.exists(): 69 | self.log(f"✗ Directory not found: {self.target_dir}") 70 | return 71 | 72 | self.log("="*70) 73 | self.log(f"{'DRY RUN - ' if dry_run else ''}Organizing files in: {self.target_dir}") 74 | self.log("="*70) 75 | 76 | # Get all files (excluding directories) 77 | files = [f for f in self.target_dir.iterdir() if f.is_file()] 78 | 79 | if not files: 80 | self.log("✗ No files found to organize.") 81 | return 82 | 83 | # Track moves for undo functionality 84 | moves = [] 85 | stats = {} 86 | 87 | for file_path in files: 88 | # Skip hidden files and log files 89 | if file_path.name.startswith('.') or file_path.name in [self.history_file, self.log_file]: 90 | continue 91 | 92 | category = self.get_file_category(file_path) 93 | 94 | # Create category folder if it doesn't exist 95 | category_folder = self.target_dir / category 96 | 97 | if not dry_run and not category_folder.exists(): 98 | category_folder.mkdir(parents=True, exist_ok=True) 99 | 100 | # Destination path 101 | dest_path = category_folder / file_path.name 102 | 103 | # Handle duplicate filenames 104 | counter = 1 105 | original_dest = dest_path 106 | while dest_path.exists() and not dry_run: 107 | name = original_dest.stem 108 | ext = original_dest.suffix 109 | dest_path = category_folder / f"{name}_{counter}{ext}" 110 | counter += 1 111 | 112 | # Move file 113 | if dry_run: 114 | self.log(f"[PREVIEW] {file_path.name} → {category}/") 115 | else: 116 | try: 117 | shutil.move(str(file_path), str(dest_path)) 118 | self.log(f"✓ Moved: {file_path.name} → {category}/") 119 | moves.append({ 120 | 'source': str(dest_path), 121 | 'original': str(file_path) 122 | }) 123 | except Exception as e: 124 | self.log(f"✗ Error moving {file_path.name}: {e}") 125 | 126 | # Update statistics 127 | stats[category] = stats.get(category, 0) + 1 128 | 129 | # Save history for undo 130 | if not dry_run and moves: 131 | self.save_history(moves) 132 | 133 | # Print statistics 134 | self.log("\n" + "="*70) 135 | self.log("SUMMARY") 136 | self.log("="*70) 137 | for category, count in sorted(stats.items()): 138 | self.log(f"{category}: {count} file(s)") 139 | self.log(f"\nTotal files {'previewed' if dry_run else 'organized'}: {sum(stats.values())}") 140 | self.log("="*70) 141 | 142 | def save_history(self, moves): 143 | """Save move history for undo functionality""" 144 | history = { 145 | 'timestamp': datetime.now().isoformat(), 146 | 'moves': moves 147 | } 148 | 149 | with open(self.history_file, 'w') as f: 150 | json.dump(history, f, indent=4) 151 | 152 | self.log(f"✓ History saved. Use 'undo' to reverse changes.") 153 | 154 | def undo_last_organization(self): 155 | """Undo last file organization""" 156 | if not os.path.exists(self.history_file): 157 | self.log("✗ No history found. Nothing to undo.") 158 | return 159 | 160 | try: 161 | with open(self.history_file, 'r') as f: 162 | history = json.load(f) 163 | except json.JSONDecodeError: 164 | self.log("✗ Error reading history file.") 165 | return 166 | 167 | self.log("="*70) 168 | self.log("UNDOING LAST ORGANIZATION") 169 | self.log("="*70) 170 | 171 | moves = history.get('moves', []) 172 | success_count = 0 173 | 174 | for move in moves: 175 | source = Path(move['source']) 176 | original = Path(move['original']) 177 | 178 | if source.exists(): 179 | try: 180 | shutil.move(str(source), str(original)) 181 | self.log(f"✓ Restored: {source.name} → {original.parent.name}/") 182 | success_count += 1 183 | except Exception as e: 184 | self.log(f"✗ Error restoring {source.name}: {e}") 185 | else: 186 | self.log(f"✗ File not found: {source.name}") 187 | 188 | # Remove empty category folders 189 | for category in self.file_categories.keys(): 190 | category_folder = self.target_dir / category 191 | if category_folder.exists() and not any(category_folder.iterdir()): 192 | category_folder.rmdir() 193 | self.log(f"✓ Removed empty folder: {category}/") 194 | 195 | # Delete history file 196 | os.remove(self.history_file) 197 | 198 | self.log("="*70) 199 | self.log(f"✓ Undo complete! Restored {success_count} file(s).") 200 | self.log("="*70) 201 | 202 | def show_statistics(self): 203 | """Show current directory statistics""" 204 | self.log("="*70) 205 | self.log(f"DIRECTORY STATISTICS: {self.target_dir}") 206 | self.log("="*70) 207 | 208 | # Count files by category 209 | stats = {} 210 | total_files = 0 211 | total_size = 0 212 | 213 | for item in self.target_dir.rglob('*'): 214 | if item.is_file(): 215 | # Skip hidden and log files 216 | if item.name.startswith('.') or item.name in [self.history_file, self.log_file]: 217 | continue 218 | 219 | category = self.get_file_category(item) 220 | stats[category] = stats.get(category, 0) + 1 221 | total_files += 1 222 | total_size += item.stat().st_size 223 | 224 | if not stats: 225 | self.log("✗ No files found.") 226 | return 227 | 228 | # Print statistics 229 | self.log(f"{'Category':<20} {'Count':>10}") 230 | self.log("-"*70) 231 | for category in sorted(stats.keys()): 232 | self.log(f"{category:<20} {stats[category]:>10}") 233 | 234 | self.log("-"*70) 235 | self.log(f"{'Total Files':<20} {total_files:>10}") 236 | self.log(f"{'Total Size':<20} {self.format_size(total_size):>10}") 237 | self.log("="*70) 238 | 239 | def format_size(self, size): 240 | """Format file size in human-readable format""" 241 | for unit in ['B', 'KB', 'MB', 'GB', 'TB']: 242 | if size < 1024.0: 243 | return f"{size:.2f} {unit}" 244 | size /= 1024.0 245 | return f"{size:.2f} PB" 246 | 247 | def clean_empty_folders(self): 248 | """Remove empty category folders""" 249 | self.log("="*70) 250 | self.log("CLEANING EMPTY FOLDERS") 251 | self.log("="*70) 252 | 253 | removed_count = 0 254 | for category in self.file_categories.keys(): 255 | category_folder = self.target_dir / category 256 | if category_folder.exists() and category_folder.is_dir(): 257 | if not any(category_folder.iterdir()): 258 | category_folder.rmdir() 259 | self.log(f"✓ Removed: {category}/") 260 | removed_count += 1 261 | 262 | if removed_count == 0: 263 | self.log("✓ No empty folders found.") 264 | else: 265 | self.log(f"✓ Removed {removed_count} empty folder(s).") 266 | self.log("="*70) 267 | 268 | def show_menu(): 269 | """Display main menu""" 270 | print("\n" + "="*70) 271 | print("📁 FILE ORGANIZER 📁".center(70)) 272 | print("="*70) 273 | print("1. Organize Files") 274 | print("2. Preview Organization (Dry Run)") 275 | print("3. Undo Last Organization") 276 | print("4. Show Statistics") 277 | print("5. Clean Empty Folders") 278 | print("6. Change Target Directory") 279 | print("7. Exit") 280 | print("="*70) 281 | 282 | def main(): 283 | """Main program""" 284 | print("="*70) 285 | print("📁 FILE ORGANIZER 📁".center(70)) 286 | print("="*70) 287 | print("Automatically organize your files into categorized folders!") 288 | 289 | organizer = FileOrganizer() 290 | 291 | while True: 292 | show_menu() 293 | print(f"\nCurrent directory: {organizer.target_dir}") 294 | choice = input("\nEnter your choice (1-7): ").strip() 295 | 296 | if choice == '1': 297 | confirm = input(f"\nOrganize files in '{organizer.target_dir}'? (y/n): ") 298 | if confirm.lower() == 'y': 299 | organizer.organize_files(dry_run=False) 300 | else: 301 | print("✗ Cancelled.") 302 | 303 | elif choice == '2': 304 | organizer.organize_files(dry_run=True) 305 | 306 | elif choice == '3': 307 | confirm = input("\nUndo last organization? (y/n): ") 308 | if confirm.lower() == 'y': 309 | organizer.undo_last_organization() 310 | else: 311 | print("✗ Cancelled.") 312 | 313 | elif choice == '4': 314 | organizer.show_statistics() 315 | 316 | elif choice == '5': 317 | organizer.clean_empty_folders() 318 | 319 | elif choice == '6': 320 | new_dir = input("\nEnter new target directory path: ").strip() 321 | new_path = Path(new_dir) 322 | if new_path.exists() and new_path.is_dir(): 323 | organizer.target_dir = new_path 324 | print(f"✓ Directory changed to: {new_path}") 325 | else: 326 | print("✗ Invalid directory path.") 327 | 328 | elif choice == '7': 329 | print("\n👋 Goodbye! Keep your files organized!") 330 | break 331 | 332 | else: 333 | print("✗ Invalid choice. Please try again.") 334 | 335 | if __name__ == "__main__": 336 | main() 337 | -------------------------------------------------------------------------------- /expense-tracker/expense_tracker.py: -------------------------------------------------------------------------------- 1 | """ 2 | Expense Tracker - Track daily expenses with charts 3 | Features: 4 | - Add expenses with category and amount 5 | - View all expenses 6 | - Filter by date range or category 7 | - Calculate total spending 8 | - Visualize expenses with charts (pie chart by category, line chart over time) 9 | - Export data to CSV 10 | - Monthly/yearly summaries 11 | """ 12 | 13 | import json 14 | import os 15 | from datetime import datetime, timedelta 16 | import csv 17 | 18 | try: 19 | import matplotlib.pyplot as plt 20 | MATPLOTLIB_AVAILABLE = True 21 | except ImportError: 22 | MATPLOTLIB_AVAILABLE = False 23 | print("Note: matplotlib not installed. Charts will not be available.") 24 | print("Install with: pip install matplotlib") 25 | 26 | class ExpenseTracker: 27 | def __init__(self): 28 | self.data_file = "expenses.json" 29 | self.categories = [ 30 | "Food & Dining", 31 | "Transportation", 32 | "Shopping", 33 | "Entertainment", 34 | "Bills & Utilities", 35 | "Healthcare", 36 | "Education", 37 | "Travel", 38 | "Other" 39 | ] 40 | 41 | def load_expenses(self): 42 | """Load expenses from file""" 43 | if not os.path.exists(self.data_file): 44 | return [] 45 | try: 46 | with open(self.data_file, 'r') as f: 47 | return json.load(f) 48 | except json.JSONDecodeError: 49 | return [] 50 | 51 | def save_expenses(self, expenses): 52 | """Save expenses to file""" 53 | with open(self.data_file, 'w') as f: 54 | json.dump(expenses, f, indent=4) 55 | 56 | def add_expense(self): 57 | """Add a new expense""" 58 | print("\n" + "="*50) 59 | print("ADD NEW EXPENSE".center(50)) 60 | print("="*50) 61 | 62 | # Get expense details 63 | description = input("Description: ").strip() 64 | 65 | # Select category 66 | print("\nCategories:") 67 | for idx, cat in enumerate(self.categories, 1): 68 | print(f"{idx}. {cat}") 69 | 70 | while True: 71 | try: 72 | cat_choice = int(input("\nSelect category (1-9): ")) 73 | if 1 <= cat_choice <= len(self.categories): 74 | category = self.categories[cat_choice - 1] 75 | break 76 | else: 77 | print("Invalid choice. Try again.") 78 | except ValueError: 79 | print("Please enter a number.") 80 | 81 | # Get amount 82 | while True: 83 | try: 84 | amount = float(input("Amount ($): ")) 85 | if amount > 0: 86 | break 87 | else: 88 | print("Amount must be positive.") 89 | except ValueError: 90 | print("Please enter a valid number.") 91 | 92 | # Get date 93 | date_input = input("Date (YYYY-MM-DD) or press Enter for today: ").strip() 94 | if date_input: 95 | try: 96 | date_obj = datetime.strptime(date_input, "%Y-%m-%d") 97 | date = date_obj.strftime("%Y-%m-%d") 98 | except ValueError: 99 | print("Invalid date format. Using today's date.") 100 | date = datetime.now().strftime("%Y-%m-%d") 101 | else: 102 | date = datetime.now().strftime("%Y-%m-%d") 103 | 104 | # Create expense entry 105 | expense = { 106 | 'id': datetime.now().timestamp(), 107 | 'date': date, 108 | 'description': description, 109 | 'category': category, 110 | 'amount': amount 111 | } 112 | 113 | # Save expense 114 | expenses = self.load_expenses() 115 | expenses.append(expense) 116 | self.save_expenses(expenses) 117 | 118 | print(f"\n✓ Expense added successfully! (${amount:.2f} for {category})") 119 | 120 | def view_expenses(self): 121 | """View all expenses""" 122 | expenses = self.load_expenses() 123 | 124 | if not expenses: 125 | print("\n✗ No expenses recorded yet.") 126 | return 127 | 128 | print("\n" + "="*90) 129 | print("ALL EXPENSES".center(90)) 130 | print("="*90) 131 | print(f"{'Date':<12} {'Description':<25} {'Category':<20} {'Amount':>10}") 132 | print("-"*90) 133 | 134 | total = 0 135 | for expense in sorted(expenses, key=lambda x: x['date'], reverse=True): 136 | print(f"{expense['date']:<12} {expense['description'][:24]:<25} " 137 | f"{expense['category']:<20} ${expense['amount']:>9.2f}") 138 | total += expense['amount'] 139 | 140 | print("-"*90) 141 | print(f"{'TOTAL':<57} ${total:>9.2f}") 142 | print("="*90) 143 | 144 | def filter_by_category(self): 145 | """Filter expenses by category""" 146 | print("\n=== Filter by Category ===") 147 | print("\nCategories:") 148 | for idx, cat in enumerate(self.categories, 1): 149 | print(f"{idx}. {cat}") 150 | 151 | try: 152 | cat_choice = int(input("\nSelect category (1-9): ")) 153 | if 1 <= cat_choice <= len(self.categories): 154 | category = self.categories[cat_choice - 1] 155 | else: 156 | print("Invalid choice.") 157 | return 158 | except ValueError: 159 | print("Invalid input.") 160 | return 161 | 162 | expenses = self.load_expenses() 163 | filtered = [e for e in expenses if e['category'] == category] 164 | 165 | if not filtered: 166 | print(f"\n✗ No expenses found for category: {category}") 167 | return 168 | 169 | print("\n" + "="*90) 170 | print(f"EXPENSES - {category.upper()}".center(90)) 171 | print("="*90) 172 | print(f"{'Date':<12} {'Description':<40} {'Amount':>10}") 173 | print("-"*90) 174 | 175 | total = 0 176 | for expense in sorted(filtered, key=lambda x: x['date'], reverse=True): 177 | print(f"{expense['date']:<12} {expense['description'][:39]:<40} ${expense['amount']:>9.2f}") 178 | total += expense['amount'] 179 | 180 | print("-"*90) 181 | print(f"{'TOTAL':<52} ${total:>9.2f}") 182 | print("="*90) 183 | 184 | def monthly_summary(self): 185 | """Show monthly summary""" 186 | print("\n=== Monthly Summary ===") 187 | month_input = input("Enter month (YYYY-MM) or press Enter for current month: ").strip() 188 | 189 | if month_input: 190 | try: 191 | datetime.strptime(month_input, "%Y-%m") 192 | target_month = month_input 193 | except ValueError: 194 | print("Invalid format. Using current month.") 195 | target_month = datetime.now().strftime("%Y-%m") 196 | else: 197 | target_month = datetime.now().strftime("%Y-%m") 198 | 199 | expenses = self.load_expenses() 200 | monthly_expenses = [e for e in expenses if e['date'].startswith(target_month)] 201 | 202 | if not monthly_expenses: 203 | print(f"\n✗ No expenses found for {target_month}") 204 | return 205 | 206 | # Calculate category totals 207 | category_totals = {} 208 | for expense in monthly_expenses: 209 | cat = expense['category'] 210 | category_totals[cat] = category_totals.get(cat, 0) + expense['amount'] 211 | 212 | total = sum(category_totals.values()) 213 | 214 | print("\n" + "="*60) 215 | print(f"SUMMARY FOR {target_month}".center(60)) 216 | print("="*60) 217 | print(f"{'Category':<30} {'Amount':>15} {'Percentage':>10}") 218 | print("-"*60) 219 | 220 | for cat in sorted(category_totals.keys(), key=lambda x: category_totals[x], reverse=True): 221 | amount = category_totals[cat] 222 | percentage = (amount / total) * 100 223 | print(f"{cat:<30} ${amount:>14.2f} {percentage:>9.1f}%") 224 | 225 | print("-"*60) 226 | print(f"{'TOTAL':<30} ${total:>14.2f}") 227 | print("="*60) 228 | 229 | def visualize_expenses(self): 230 | """Create charts for expenses""" 231 | if not MATPLOTLIB_AVAILABLE: 232 | print("\n✗ matplotlib not installed. Cannot create charts.") 233 | print("Install with: pip install matplotlib") 234 | return 235 | 236 | expenses = self.load_expenses() 237 | 238 | if not expenses: 239 | print("\n✗ No expenses to visualize.") 240 | return 241 | 242 | print("\n=== Visualize Expenses ===") 243 | print("1. Pie Chart (by Category)") 244 | print("2. Line Chart (Over Time)") 245 | print("3. Bar Chart (Monthly Comparison)") 246 | 247 | choice = input("\nSelect chart type (1-3): ").strip() 248 | 249 | if choice == '1': 250 | self._pie_chart(expenses) 251 | elif choice == '2': 252 | self._line_chart(expenses) 253 | elif choice == '3': 254 | self._bar_chart(expenses) 255 | else: 256 | print("Invalid choice.") 257 | 258 | def _pie_chart(self, expenses): 259 | """Create pie chart by category""" 260 | category_totals = {} 261 | for expense in expenses: 262 | cat = expense['category'] 263 | category_totals[cat] = category_totals.get(cat, 0) + expense['amount'] 264 | 265 | categories = list(category_totals.keys()) 266 | amounts = list(category_totals.values()) 267 | 268 | plt.figure(figsize=(10, 8)) 269 | plt.pie(amounts, labels=categories, autopct='%1.1f%%', startangle=90) 270 | plt.title('Expenses by Category', fontsize=16, fontweight='bold') 271 | plt.axis('equal') 272 | plt.tight_layout() 273 | plt.show() 274 | print("✓ Chart displayed!") 275 | 276 | def _line_chart(self, expenses): 277 | """Create line chart over time""" 278 | # Sort by date 279 | sorted_expenses = sorted(expenses, key=lambda x: x['date']) 280 | 281 | # Group by date 282 | date_totals = {} 283 | for expense in sorted_expenses: 284 | date = expense['date'] 285 | date_totals[date] = date_totals.get(date, 0) + expense['amount'] 286 | 287 | dates = list(date_totals.keys()) 288 | amounts = list(date_totals.values()) 289 | 290 | plt.figure(figsize=(12, 6)) 291 | plt.plot(dates, amounts, marker='o', linewidth=2, markersize=6) 292 | plt.xlabel('Date', fontsize=12) 293 | plt.ylabel('Amount ($)', fontsize=12) 294 | plt.title('Expenses Over Time', fontsize=16, fontweight='bold') 295 | plt.xticks(rotation=45) 296 | plt.grid(True, alpha=0.3) 297 | plt.tight_layout() 298 | plt.show() 299 | print("✓ Chart displayed!") 300 | 301 | def _bar_chart(self, expenses): 302 | """Create bar chart for monthly comparison""" 303 | # Group by month 304 | monthly_totals = {} 305 | for expense in expenses: 306 | month = expense['date'][:7] # YYYY-MM 307 | monthly_totals[month] = monthly_totals.get(month, 0) + expense['amount'] 308 | 309 | months = sorted(monthly_totals.keys()) 310 | amounts = [monthly_totals[m] for m in months] 311 | 312 | plt.figure(figsize=(12, 6)) 313 | plt.bar(months, amounts, color='skyblue', edgecolor='navy') 314 | plt.xlabel('Month', fontsize=12) 315 | plt.ylabel('Total Amount ($)', fontsize=12) 316 | plt.title('Monthly Expenses Comparison', fontsize=16, fontweight='bold') 317 | plt.xticks(rotation=45) 318 | plt.grid(True, axis='y', alpha=0.3) 319 | plt.tight_layout() 320 | plt.show() 321 | print("✓ Chart displayed!") 322 | 323 | def export_to_csv(self): 324 | """Export expenses to CSV""" 325 | expenses = self.load_expenses() 326 | 327 | if not expenses: 328 | print("\n✗ No expenses to export.") 329 | return 330 | 331 | filename = f"expenses_export_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv" 332 | 333 | with open(filename, 'w', newline='') as csvfile: 334 | fieldnames = ['date', 'description', 'category', 'amount'] 335 | writer = csv.DictWriter(csvfile, fieldnames=fieldnames) 336 | 337 | writer.writeheader() 338 | for expense in sorted(expenses, key=lambda x: x['date']): 339 | writer.writerow({ 340 | 'date': expense['date'], 341 | 'description': expense['description'], 342 | 'category': expense['category'], 343 | 'amount': expense['amount'] 344 | }) 345 | 346 | print(f"\n✓ Expenses exported to: {filename}") 347 | 348 | def delete_expense(self): 349 | """Delete an expense""" 350 | expenses = self.load_expenses() 351 | 352 | if not expenses: 353 | print("\n✗ No expenses to delete.") 354 | return 355 | 356 | print("\n=== Recent Expenses ===") 357 | recent = sorted(expenses, key=lambda x: x['date'], reverse=True)[:10] 358 | 359 | for idx, expense in enumerate(recent, 1): 360 | print(f"{idx}. {expense['date']} - {expense['description']} " 361 | f"({expense['category']}) - ${expense['amount']:.2f}") 362 | 363 | try: 364 | choice = int(input("\nEnter expense number to delete (0 to cancel): ")) 365 | if choice == 0: 366 | return 367 | if 1 <= choice <= len(recent): 368 | expense_to_delete = recent[choice - 1] 369 | expenses = [e for e in expenses if e['id'] != expense_to_delete['id']] 370 | self.save_expenses(expenses) 371 | print(f"✓ Expense deleted successfully!") 372 | else: 373 | print("Invalid choice.") 374 | except ValueError: 375 | print("Invalid input.") 376 | 377 | def show_menu(self): 378 | """Display main menu""" 379 | print("\n" + "="*50) 380 | print("💰 EXPENSE TRACKER 💰".center(50)) 381 | print("="*50) 382 | print("1. Add Expense") 383 | print("2. View All Expenses") 384 | print("3. Filter by Category") 385 | print("4. Monthly Summary") 386 | print("5. Visualize Expenses (Charts)") 387 | print("6. Export to CSV") 388 | print("7. Delete Expense") 389 | print("8. Exit") 390 | print("="*50) 391 | 392 | def run(self): 393 | """Main program loop""" 394 | print("="*50) 395 | print("💰 EXPENSE TRACKER 💰".center(50)) 396 | print("="*50) 397 | print("Track your daily expenses and visualize spending!") 398 | 399 | while True: 400 | self.show_menu() 401 | choice = input("\nEnter your choice (1-8): ").strip() 402 | 403 | if choice == '1': 404 | self.add_expense() 405 | elif choice == '2': 406 | self.view_expenses() 407 | elif choice == '3': 408 | self.filter_by_category() 409 | elif choice == '4': 410 | self.monthly_summary() 411 | elif choice == '5': 412 | self.visualize_expenses() 413 | elif choice == '6': 414 | self.export_to_csv() 415 | elif choice == '7': 416 | self.delete_expense() 417 | elif choice == '8': 418 | print("\n👋 Goodbye! Keep tracking your expenses!") 419 | break 420 | else: 421 | print("✗ Invalid choice. Please try again.") 422 | 423 | if __name__ == "__main__": 424 | tracker = ExpenseTracker() 425 | tracker.run() 426 | -------------------------------------------------------------------------------- /currency-converter/currency_converter.py: -------------------------------------------------------------------------------- 1 | """ 2 | Currency Converter - Real-time exchange rates 3 | Features: 4 | - Real-time currency conversion using live exchange rates 5 | - Support for 150+ currencies 6 | - Historical exchange rates 7 | - Offline mode with cached rates 8 | - GUI interface with Tkinter 9 | - Favorite currency pairs 10 | - Conversion history 11 | """ 12 | 13 | import tkinter as tk 14 | from tkinter import ttk, messagebox 15 | import requests 16 | import json 17 | import os 18 | from datetime import datetime, timedelta 19 | 20 | class CurrencyConverter: 21 | def __init__(self, root): 22 | self.root = root 23 | self.root.title("💱 Currency Converter") 24 | self.root.geometry("600x700") 25 | self.root.resizable(False, False) 26 | self.root.configure(bg='#2C3E50') 27 | 28 | # API endpoint (free tier - no API key needed) 29 | self.api_url = "https://api.exchangerate-api.com/v4/latest/" 30 | 31 | # Cache settings 32 | self.cache_file = "exchange_rates_cache.json" 33 | self.cache_duration = timedelta(hours=6) # Cache for 6 hours 34 | 35 | # History file 36 | self.history_file = "conversion_history.json" 37 | 38 | # Popular currencies 39 | self.popular_currencies = [ 40 | 'USD', 'EUR', 'GBP', 'JPY', 'AUD', 'CAD', 'CHF', 'CNY', 'INR', 'MXN' 41 | ] 42 | 43 | # Load data 44 | self.exchange_rates = {} 45 | self.currencies = [] 46 | self.load_exchange_rates() 47 | 48 | # Create UI 49 | self.create_widgets() 50 | 51 | def create_widgets(self): 52 | """Create all UI widgets""" 53 | 54 | # Title 55 | title_label = tk.Label( 56 | self.root, 57 | text="💱 CURRENCY CONVERTER", 58 | font=('Helvetica', 24, 'bold'), 59 | bg='#2C3E50', 60 | fg='#ECF0F1' 61 | ) 62 | title_label.pack(pady=20) 63 | 64 | # Main conversion frame 65 | conv_frame = tk.Frame(self.root, bg='#34495E', bd=5, relief='ridge') 66 | conv_frame.pack(pady=10, padx=30, fill='both') 67 | 68 | # Amount input 69 | amount_label = tk.Label( 70 | conv_frame, 71 | text="Amount:", 72 | font=('Helvetica', 14), 73 | bg='#34495E', 74 | fg='#ECF0F1' 75 | ) 76 | amount_label.grid(row=0, column=0, padx=10, pady=15, sticky='w') 77 | 78 | self.amount_entry = tk.Entry( 79 | conv_frame, 80 | font=('Helvetica', 16), 81 | width=20, 82 | bd=2, 83 | relief='solid' 84 | ) 85 | self.amount_entry.grid(row=0, column=1, padx=10, pady=15) 86 | self.amount_entry.insert(0, "1.00") 87 | 88 | # From currency 89 | from_label = tk.Label( 90 | conv_frame, 91 | text="From:", 92 | font=('Helvetica', 14), 93 | bg='#34495E', 94 | fg='#ECF0F1' 95 | ) 96 | from_label.grid(row=1, column=0, padx=10, pady=15, sticky='w') 97 | 98 | self.from_currency = ttk.Combobox( 99 | conv_frame, 100 | values=self.currencies, 101 | font=('Helvetica', 12), 102 | width=18, 103 | state='readonly' 104 | ) 105 | self.from_currency.grid(row=1, column=1, padx=10, pady=15) 106 | self.from_currency.set('USD') 107 | 108 | # Swap button 109 | swap_button = tk.Button( 110 | conv_frame, 111 | text="⇅", 112 | command=self.swap_currencies, 113 | font=('Helvetica', 20, 'bold'), 114 | bg='#3498DB', 115 | fg='white', 116 | width=3, 117 | relief='raised', 118 | bd=2, 119 | cursor='hand2' 120 | ) 121 | swap_button.grid(row=2, column=1, pady=5) 122 | 123 | # To currency 124 | to_label = tk.Label( 125 | conv_frame, 126 | text="To:", 127 | font=('Helvetica', 14), 128 | bg='#34495E', 129 | fg='#ECF0F1' 130 | ) 131 | to_label.grid(row=3, column=0, padx=10, pady=15, sticky='w') 132 | 133 | self.to_currency = ttk.Combobox( 134 | conv_frame, 135 | values=self.currencies, 136 | font=('Helvetica', 12), 137 | width=18, 138 | state='readonly' 139 | ) 140 | self.to_currency.grid(row=3, column=1, padx=10, pady=15) 141 | self.to_currency.set('EUR') 142 | 143 | # Convert button 144 | convert_button = tk.Button( 145 | self.root, 146 | text="🔄 CONVERT", 147 | command=self.convert_currency, 148 | font=('Helvetica', 16, 'bold'), 149 | bg='#27AE60', 150 | fg='white', 151 | width=20, 152 | height=2, 153 | relief='raised', 154 | bd=3, 155 | cursor='hand2' 156 | ) 157 | convert_button.pack(pady=20) 158 | 159 | # Result frame 160 | result_frame = tk.Frame(self.root, bg='#34495E', bd=5, relief='ridge') 161 | result_frame.pack(pady=10, padx=30, fill='both') 162 | 163 | self.result_label = tk.Label( 164 | result_frame, 165 | text="Enter amount and click Convert", 166 | font=('Helvetica', 18, 'bold'), 167 | bg='#34495E', 168 | fg='#ECF0F1', 169 | wraplength=500 170 | ) 171 | self.result_label.pack(pady=30) 172 | 173 | # Exchange rate info 174 | self.rate_label = tk.Label( 175 | result_frame, 176 | text="", 177 | font=('Helvetica', 12), 178 | bg='#34495E', 179 | fg='#BDC3C7' 180 | ) 181 | self.rate_label.pack(pady=10) 182 | 183 | # Button frame 184 | button_frame = tk.Frame(self.root, bg='#2C3E50') 185 | button_frame.pack(pady=10) 186 | 187 | # Refresh rates button 188 | refresh_button = tk.Button( 189 | button_frame, 190 | text="🔃 Refresh Rates", 191 | command=self.refresh_rates, 192 | font=('Helvetica', 11), 193 | bg='#E67E22', 194 | fg='white', 195 | width=15, 196 | relief='raised', 197 | bd=2, 198 | cursor='hand2' 199 | ) 200 | refresh_button.grid(row=0, column=0, padx=5) 201 | 202 | # History button 203 | history_button = tk.Button( 204 | button_frame, 205 | text="📜 History", 206 | command=self.show_history, 207 | font=('Helvetica', 11), 208 | bg='#9B59B6', 209 | fg='white', 210 | width=15, 211 | relief='raised', 212 | bd=2, 213 | cursor='hand2' 214 | ) 215 | history_button.grid(row=0, column=1, padx=5) 216 | 217 | # Status label 218 | self.status_label = tk.Label( 219 | self.root, 220 | text="", 221 | font=('Helvetica', 10), 222 | bg='#2C3E50', 223 | fg='#95A5A6' 224 | ) 225 | self.status_label.pack(pady=10) 226 | 227 | # Popular currencies frame 228 | popular_frame = tk.LabelFrame( 229 | self.root, 230 | text="Quick Convert (1 USD to...)", 231 | font=('Helvetica', 11, 'bold'), 232 | bg='#34495E', 233 | fg='#ECF0F1', 234 | bd=3 235 | ) 236 | popular_frame.pack(pady=10, padx=30, fill='both') 237 | 238 | self.popular_labels = {} 239 | for i, currency in enumerate(self.popular_currencies[1:6]): # Show top 5 240 | label = tk.Label( 241 | popular_frame, 242 | text=f"{currency}: ...", 243 | font=('Helvetica', 10), 244 | bg='#34495E', 245 | fg='#ECF0F1', 246 | anchor='w' 247 | ) 248 | label.grid(row=i//2, column=i%2, padx=10, pady=5, sticky='w') 249 | self.popular_labels[currency] = label 250 | 251 | self.update_popular_rates() 252 | 253 | def load_exchange_rates(self): 254 | """Load exchange rates from cache or API""" 255 | # Try loading from cache first 256 | if os.path.exists(self.cache_file): 257 | try: 258 | with open(self.cache_file, 'r') as f: 259 | cache_data = json.load(f) 260 | 261 | # Check if cache is still valid 262 | cache_time = datetime.fromisoformat(cache_data['timestamp']) 263 | if datetime.now() - cache_time < self.cache_duration: 264 | self.exchange_rates = cache_data['rates'] 265 | self.currencies = sorted(self.exchange_rates.keys()) 266 | self.update_status(f"Using cached rates (updated: {cache_time.strftime('%Y-%m-%d %H:%M')})") 267 | return 268 | except: 269 | pass 270 | 271 | # Fetch from API 272 | self.refresh_rates() 273 | 274 | def refresh_rates(self): 275 | """Fetch latest exchange rates from API""" 276 | try: 277 | self.update_status("Fetching latest rates...") 278 | response = requests.get(f"{self.api_url}USD", timeout=10) 279 | 280 | if response.status_code == 200: 281 | data = response.json() 282 | self.exchange_rates = data['rates'] 283 | self.currencies = sorted(self.exchange_rates.keys()) 284 | 285 | # Update comboboxes 286 | self.from_currency['values'] = self.currencies 287 | self.to_currency['values'] = self.currencies 288 | 289 | # Save to cache 290 | cache_data = { 291 | 'timestamp': datetime.now().isoformat(), 292 | 'rates': self.exchange_rates 293 | } 294 | with open(self.cache_file, 'w') as f: 295 | json.dump(cache_data, f, indent=4) 296 | 297 | self.update_status("✓ Rates updated successfully!") 298 | self.update_popular_rates() 299 | messagebox.showinfo("Success", "Exchange rates updated successfully!") 300 | else: 301 | raise Exception("Failed to fetch rates") 302 | 303 | except Exception as e: 304 | self.update_status(f"✗ Error: {str(e)}") 305 | messagebox.showerror("Error", "Failed to fetch exchange rates.\nUsing cached rates if available.") 306 | 307 | def convert_currency(self): 308 | """Perform currency conversion""" 309 | try: 310 | # Get input values 311 | amount = float(self.amount_entry.get()) 312 | from_curr = self.from_currency.get() 313 | to_curr = self.to_currency.get() 314 | 315 | if not from_curr or not to_curr: 316 | messagebox.showwarning("Warning", "Please select both currencies") 317 | return 318 | 319 | # Convert to USD first, then to target currency 320 | if from_curr != 'USD': 321 | amount_in_usd = amount / self.exchange_rates[from_curr] 322 | else: 323 | amount_in_usd = amount 324 | 325 | # Convert to target currency 326 | if to_curr != 'USD': 327 | result = amount_in_usd * self.exchange_rates[to_curr] 328 | else: 329 | result = amount_in_usd 330 | 331 | # Calculate exchange rate 332 | if from_curr != 'USD': 333 | rate = self.exchange_rates[to_curr] / self.exchange_rates[from_curr] 334 | else: 335 | rate = self.exchange_rates[to_curr] 336 | 337 | # Display result 338 | self.result_label.config( 339 | text=f"{amount:,.2f} {from_curr} = {result:,.2f} {to_curr}", 340 | fg='#2ECC71' 341 | ) 342 | 343 | self.rate_label.config( 344 | text=f"Exchange Rate: 1 {from_curr} = {rate:.6f} {to_curr}" 345 | ) 346 | 347 | # Save to history 348 | self.save_to_history(amount, from_curr, result, to_curr, rate) 349 | 350 | except ValueError: 351 | messagebox.showerror("Error", "Please enter a valid number") 352 | except KeyError: 353 | messagebox.showerror("Error", "Currency not found in database") 354 | except Exception as e: 355 | messagebox.showerror("Error", f"Conversion failed: {str(e)}") 356 | 357 | def swap_currencies(self): 358 | """Swap from and to currencies""" 359 | from_val = self.from_currency.get() 360 | to_val = self.to_currency.get() 361 | 362 | self.from_currency.set(to_val) 363 | self.to_currency.set(from_val) 364 | 365 | def update_popular_rates(self): 366 | """Update quick convert display""" 367 | try: 368 | for currency in list(self.popular_labels.keys()): 369 | if currency in self.exchange_rates: 370 | rate = self.exchange_rates[currency] 371 | self.popular_labels[currency].config( 372 | text=f"{currency}: {rate:.4f}" 373 | ) 374 | except: 375 | pass 376 | 377 | def save_to_history(self, amount, from_curr, result, to_curr, rate): 378 | """Save conversion to history""" 379 | history = [] 380 | 381 | if os.path.exists(self.history_file): 382 | try: 383 | with open(self.history_file, 'r') as f: 384 | history = json.load(f) 385 | except: 386 | history = [] 387 | 388 | entry = { 389 | 'timestamp': datetime.now().isoformat(), 390 | 'amount': amount, 391 | 'from': from_curr, 392 | 'result': result, 393 | 'to': to_curr, 394 | 'rate': rate 395 | } 396 | 397 | history.insert(0, entry) # Add to beginning 398 | history = history[:50] # Keep last 50 conversions 399 | 400 | with open(self.history_file, 'w') as f: 401 | json.dump(history, f, indent=4) 402 | 403 | def show_history(self): 404 | """Display conversion history""" 405 | if not os.path.exists(self.history_file): 406 | messagebox.showinfo("History", "No conversion history yet.") 407 | return 408 | 409 | try: 410 | with open(self.history_file, 'r') as f: 411 | history = json.load(f) 412 | 413 | if not history: 414 | messagebox.showinfo("History", "No conversion history yet.") 415 | return 416 | 417 | # Create history window 418 | history_window = tk.Toplevel(self.root) 419 | history_window.title("Conversion History") 420 | history_window.geometry("600x400") 421 | history_window.configure(bg='#2C3E50') 422 | 423 | # Title 424 | title = tk.Label( 425 | history_window, 426 | text="📜 Conversion History (Last 20)", 427 | font=('Helvetica', 16, 'bold'), 428 | bg='#2C3E50', 429 | fg='#ECF0F1' 430 | ) 431 | title.pack(pady=10) 432 | 433 | # Create scrollable text widget 434 | text_frame = tk.Frame(history_window) 435 | text_frame.pack(fill='both', expand=True, padx=10, pady=10) 436 | 437 | scrollbar = tk.Scrollbar(text_frame) 438 | scrollbar.pack(side='right', fill='y') 439 | 440 | text_widget = tk.Text( 441 | text_frame, 442 | font=('Courier', 10), 443 | bg='#34495E', 444 | fg='#ECF0F1', 445 | yscrollcommand=scrollbar.set 446 | ) 447 | text_widget.pack(side='left', fill='both', expand=True) 448 | scrollbar.config(command=text_widget.yview) 449 | 450 | # Add history entries 451 | for entry in history[:20]: 452 | timestamp = datetime.fromisoformat(entry['timestamp']) 453 | text_widget.insert('end', f"{timestamp.strftime('%Y-%m-%d %H:%M')}\n") 454 | text_widget.insert('end', f"{entry['amount']:.2f} {entry['from']} = " 455 | f"{entry['result']:.2f} {entry['to']}\n") 456 | text_widget.insert('end', f"Rate: {entry['rate']:.6f}\n") 457 | text_widget.insert('end', "-"*60 + "\n\n") 458 | 459 | text_widget.config(state='disabled') 460 | 461 | except Exception as e: 462 | messagebox.showerror("Error", f"Failed to load history: {str(e)}") 463 | 464 | def update_status(self, message): 465 | """Update status label""" 466 | self.status_label.config(text=message) 467 | self.root.update() 468 | 469 | def main(): 470 | root = tk.Tk() 471 | app = CurrencyConverter(root) 472 | root.mainloop() 473 | 474 | if __name__ == "__main__": 475 | main() 476 | --------------------------------------------------------------------------------