Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Python cache files
__pycache__/
*.py[cod]
*$py.class

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg

# PyInstaller
*.manifest
*.spec

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/

# Virtual environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# IDE files
.vscode/
.idea/
*.swp
*.swo
*~

# OS files
.DS_Store
Thumbs.db

# Temporary files
*.tmp
*.temp
/tmp/
155 changes: 155 additions & 0 deletions week1_projects/copilot/URL_Shortener/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
# πŸ”— URL Shortener (Offline)

A simple, beginner-friendly Python project that creates short codes for long URLs and stores them locally. This tool works completely offline - no internet connection required once it's running!

## πŸ“‹ What This Project Does

- **Shorten URLs**: Takes long website links and creates short, memorable codes
- **Expand URLs**: Retrieves original URLs using short codes
- **Local Storage**: Saves all mappings in a JSON file (`url_mappings.json`)
- **Statistics**: Tracks usage and provides insights
- **Offline Operation**: Works without internet connectivity

## 🎯 Features

- βœ… Generate 6-character alphanumeric short codes (e.g., `abc123`)
- βœ… Validate URL formats before shortening
- βœ… Prevent duplicate URLs (returns existing short code)
- βœ… Track access count for each shortened URL
- βœ… List all shortened URLs with metadata
- βœ… Display usage statistics
- βœ… User-friendly command-line interface
- βœ… Persistent data storage in JSON format

## πŸš€ How to Run

1. **Prerequisites**: Make sure you have Python 3.6+ installed
2. **Download**: Save the `URL_Shortener.py` file to your computer
3. **Run**: Open terminal/command prompt and navigate to the file location
4. **Execute**: Run the command:
```bash
python URL_Shortener.py
```

## πŸ’‘ How to Use

The program presents a menu with 5 options:

### 1. Shorten a URL
```
Enter the URL to shorten: https://www.example.com/very/long/path
βœ… URL shortened successfully!
πŸ”— Short code: aBc123
```

### 2. Expand a short code
```
Enter the short code: aBc123
βœ… URL retrieved successfully!
🌐 Original URL: https://www.example.com/very/long/path
```

### 3. List all URLs
Shows all shortened URLs with creation dates and access counts.

### 4. Show statistics
Displays total URLs shortened and access statistics.

### 5. Exit
Closes the program safely.

## πŸ“ Example Usage

### Input/Output Examples:

**Shortening a URL:**
```
Input: https://github.com/NeuroByte-Society/weekend_projects
Output: Short code generated β†’ K7m2Np
```

**Expanding a code:**
```
Input: K7m2Np
Output: https://github.com/NeuroByte-Society/weekend_projects
```

**Invalid URL handling:**
```
Input: not-a-valid-url
Output: ❌ Error: Invalid URL format. Please include http://, https://, or a valid domain.
```

## πŸ—‚οΈ Data Storage

The program creates a `url_mappings.json` file that stores:
- Short code mappings
- Original URLs
- Creation timestamps
- Access count for each URL

Example JSON structure:
```json
{
"K7m2Np": {
"url": "https://github.com/NeuroByte-Society/weekend_projects",
"created_at": "2024-01-15T10:30:45",
"access_count": 3
}
}
```

## πŸ› οΈ Technical Details

**Language**: Python 3.6+
**Dependencies**: Only built-in Python modules:
- `json` - For data storage
- `random` & `string` - For generating short codes
- `os` - For file operations
- `datetime` - For timestamps

**Key Functions**:
- `generate_short_code()` - Creates unique 6-character codes
- `shorten_url()` - Maps long URLs to short codes
- `expand_url()` - Retrieves original URLs
- `is_valid_url()` - Validates URL format

## πŸŽ“ What I Learned

- **File I/O**: Reading from and writing to JSON files
- **Data Validation**: Checking URL formats and handling edge cases
- **User Interface**: Creating an interactive command-line menu
- **Data Structures**: Using dictionaries for efficient key-value mapping
- **Error Handling**: Managing invalid inputs gracefully
- **Code Organization**: Structuring code with classes and methods

## πŸ”§ Possible Enhancements

- Custom short code length options
- URL expiration dates
- Import/export functionality
- Basic analytics dashboard
- QR code generation for short URLs
- Bulk URL processing

## πŸ“ File Structure

```
URL_Shortener/
β”œβ”€β”€ URL_Shortener.py # Main program file
β”œβ”€β”€ README.md # This documentation
└── url_mappings.json # Generated data file (created when first URL is shortened)
```

## 🚨 Notes

- The `url_mappings.json` file is created automatically when you shorten your first URL
- All data is stored locally - no data is sent to external servers
- Short codes are case-sensitive
- The program performs basic URL validation but doesn't verify if URLs actually exist

---

**Project by**: @copilot for NeuroByte Society Weekend Projects
**Difficulty**: Beginner-friendly
**Estimated time**: 2-3 hours
170 changes: 170 additions & 0 deletions week1_projects/copilot/URL_Shortener/URL_Shortener.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
import json
import random
import string
import os
from datetime import datetime

class URLShortener:
def __init__(self, data_file="url_mappings.json"):
"""Initialize the URL Shortener with a data file."""
self.data_file = data_file
self.url_mappings = self.load_mappings()

def load_mappings(self):
"""Load existing URL mappings from the JSON file."""
if os.path.exists(self.data_file):
try:
with open(self.data_file, 'r') as file:
return json.load(file)
except (json.JSONDecodeError, FileNotFoundError):
return {}
return {}

def save_mappings(self):
"""Save URL mappings to the JSON file."""
with open(self.data_file, 'w') as file:
json.dump(self.url_mappings, file, indent=2)

def generate_short_code(self, length=6):
"""Generate a random short code."""
characters = string.ascii_letters + string.digits
while True:
short_code = ''.join(random.choice(characters) for _ in range(length))
# Ensure the code doesn't already exist
if short_code not in self.url_mappings:
return short_code

def is_valid_url(self, url):
"""Basic URL validation."""
url = url.strip()
if not url:
return False

# Basic check for common URL patterns
valid_prefixes = ['http://', 'https://', 'ftp://', 'www.']
has_valid_prefix = any(url.lower().startswith(prefix) for prefix in valid_prefixes)

# Check if it contains a dot (basic domain check)
has_dot = '.' in url

return has_valid_prefix or has_dot

def shorten_url(self, long_url):
"""Shorten a long URL and return the short code."""
long_url = long_url.strip()

if not self.is_valid_url(long_url):
return None, "Invalid URL format. Please include http://, https://, or a valid domain."

# Check if URL already exists
for short_code, data in self.url_mappings.items():
if data['url'] == long_url:
return short_code, f"URL already shortened! Short code: {short_code}"

# Generate new short code
short_code = self.generate_short_code()

# Store the mapping with metadata
self.url_mappings[short_code] = {
'url': long_url,
'created_at': datetime.now().isoformat(),
'access_count': 0
}

# Save to file
self.save_mappings()

return short_code, "URL shortened successfully!"

def expand_url(self, short_code):
"""Expand a short code back to the original URL."""
short_code = short_code.strip()

if short_code in self.url_mappings:
# Increment access count
self.url_mappings[short_code]['access_count'] += 1
self.save_mappings()

return self.url_mappings[short_code]['url'], "URL retrieved successfully!"
else:
return None, f"Short code '{short_code}' not found."

def list_all_urls(self):
"""List all shortened URLs."""
if not self.url_mappings:
return "No URLs have been shortened yet."

result = "\n=== All Shortened URLs ===\n"
for short_code, data in self.url_mappings.items():
result += f"Short Code: {short_code}\n"
result += f"Original URL: {data['url']}\n"
result += f"Created: {data['created_at'][:19]}\n"
result += f"Access Count: {data['access_count']}\n"
result += "-" * 40 + "\n"

return result

def get_stats(self):
"""Get statistics about the URL shortener."""
total_urls = len(self.url_mappings)
total_accesses = sum(data['access_count'] for data in self.url_mappings.values())

return f"""
=== URL Shortener Statistics ===
Total URLs shortened: {total_urls}
Total accesses: {total_accesses}
Average accesses per URL: {total_accesses / total_urls if total_urls > 0 else 0:.1f}
"""

def main():
"""Main function to run the URL Shortener CLI."""
shortener = URLShortener()

print("πŸ”— Welcome to the Offline URL Shortener!")
print("=" * 40)

while True:
print("\nChoose an option:")
print("1. Shorten a URL")
print("2. Expand a short code")
print("3. List all URLs")
print("4. Show statistics")
print("5. Exit")

choice = input("\nEnter your choice (1-5): ").strip()

if choice == '1':
long_url = input("Enter the URL to shorten: ")
short_code, message = shortener.shorten_url(long_url)

if short_code:
print(f"\nβœ… {message}")
print(f"πŸ”— Short code: {short_code}")
else:
print(f"\n❌ Error: {message}")

elif choice == '2':
short_code = input("Enter the short code: ")
original_url, message = shortener.expand_url(short_code)

if original_url:
print(f"\nβœ… {message}")
print(f"🌐 Original URL: {original_url}")
else:
print(f"\n❌ Error: {message}")

elif choice == '3':
print(shortener.list_all_urls())

elif choice == '4':
print(shortener.get_stats())

elif choice == '5':
print("\nπŸ‘‹ Thank you for using the URL Shortener!")
break

else:
print("\n❌ Invalid choice. Please enter a number between 1 and 5.")

if __name__ == "__main__":
main()
Loading