dupe-hunter 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,62 @@
1
+ Metadata-Version: 2.4
2
+ Name: dupe-hunter
3
+ Version: 0.1.0
4
+ Summary: Find and remove duplicate files quickly
5
+ Author-email: lalalaleishaaa <your-email@example.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/lalalaleishaaa/dupe-hunter
8
+ Project-URL: Bug Tracker, https://github.com/lalalaleishaaa/dupe-hunter/issues
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Description-Content-Type: text/markdown
13
+ Requires-Dist: typer>=0.9.0
14
+ Requires-Dist: rich>=13.0.0
15
+ Requires-Dist: click>=8.0.0
16
+
17
+ \# 🔍 Dupe Hunter
18
+
19
+
20
+
21
+ \*\*Find and delete duplicate files in seconds!\*\*
22
+
23
+
24
+
25
+ \## Real Results
26
+
27
+
28
+
29
+ I ran this on my own computer and:
30
+
31
+ \- Found \*\*16,541 duplicate files\*\*
32
+
33
+ \- Saved \*\*3.1 GB\*\* of disk space
34
+
35
+ \- Scanned \*\*50,000+ files\*\* in minutes
36
+
37
+
38
+
39
+ \## Features
40
+
41
+
42
+
43
+ \- \*\*Blazing fast\*\* - Groups by file size first
44
+
45
+ \- \*\*Progress bars\*\* - See what's happening
46
+
47
+ \- \*\*Beautiful output\*\* - Color-coded tables
48
+
49
+ \- \*\*Space calculator\*\* - Shows how much you'll save
50
+
51
+ \- \*\*Safe delete\*\* - Keeps first file, deletes rest
52
+
53
+
54
+
55
+ \## Installation
56
+
57
+
58
+
59
+ ```bash
60
+
61
+ pip install dupe-hunter
62
+
@@ -0,0 +1,46 @@
1
+ \# 🔍 Dupe Hunter
2
+
3
+
4
+
5
+ \*\*Find and delete duplicate files in seconds!\*\*
6
+
7
+
8
+
9
+ \## Real Results
10
+
11
+
12
+
13
+ I ran this on my own computer and:
14
+
15
+ \- Found \*\*16,541 duplicate files\*\*
16
+
17
+ \- Saved \*\*3.1 GB\*\* of disk space
18
+
19
+ \- Scanned \*\*50,000+ files\*\* in minutes
20
+
21
+
22
+
23
+ \## Features
24
+
25
+
26
+
27
+ \- \*\*Blazing fast\*\* - Groups by file size first
28
+
29
+ \- \*\*Progress bars\*\* - See what's happening
30
+
31
+ \- \*\*Beautiful output\*\* - Color-coded tables
32
+
33
+ \- \*\*Space calculator\*\* - Shows how much you'll save
34
+
35
+ \- \*\*Safe delete\*\* - Keeps first file, deletes rest
36
+
37
+
38
+
39
+ \## Installation
40
+
41
+
42
+
43
+ ```bash
44
+
45
+ pip install dupe-hunter
46
+
@@ -0,0 +1,30 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "dupe-hunter"
7
+ version = "0.1.0"
8
+ description = "Find and remove duplicate files quickly"
9
+ readme = "README.md"
10
+ authors = [
11
+ {name = "lalalaleishaaa", email = "your-email@example.com"}
12
+ ]
13
+ license = {text = "MIT"}
14
+ classifiers = [
15
+ "Programming Language :: Python :: 3",
16
+ "License :: OSI Approved :: MIT License",
17
+ "Operating System :: OS Independent",
18
+ ]
19
+ dependencies = [
20
+ "typer>=0.9.0",
21
+ "rich>=13.0.0",
22
+ "click>=8.0.0"
23
+ ]
24
+
25
+ [project.urls]
26
+ Homepage = "https://github.com/lalalaleishaaa/dupe-hunter"
27
+ "Bug Tracker" = "https://github.com/lalalaleishaaa/dupe-hunter/issues"
28
+
29
+ [project.scripts]
30
+ dupe-hunter = "src.dupe_hunter:app"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,3 @@
1
+ from setuptools import setup
2
+
3
+ setup()
@@ -0,0 +1 @@
1
+ # This makes 'src' a proper Python package
@@ -0,0 +1,62 @@
1
+ Metadata-Version: 2.4
2
+ Name: dupe-hunter
3
+ Version: 0.1.0
4
+ Summary: Find and remove duplicate files quickly
5
+ Author-email: lalalaleishaaa <your-email@example.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/lalalaleishaaa/dupe-hunter
8
+ Project-URL: Bug Tracker, https://github.com/lalalaleishaaa/dupe-hunter/issues
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Description-Content-Type: text/markdown
13
+ Requires-Dist: typer>=0.9.0
14
+ Requires-Dist: rich>=13.0.0
15
+ Requires-Dist: click>=8.0.0
16
+
17
+ \# 🔍 Dupe Hunter
18
+
19
+
20
+
21
+ \*\*Find and delete duplicate files in seconds!\*\*
22
+
23
+
24
+
25
+ \## Real Results
26
+
27
+
28
+
29
+ I ran this on my own computer and:
30
+
31
+ \- Found \*\*16,541 duplicate files\*\*
32
+
33
+ \- Saved \*\*3.1 GB\*\* of disk space
34
+
35
+ \- Scanned \*\*50,000+ files\*\* in minutes
36
+
37
+
38
+
39
+ \## Features
40
+
41
+
42
+
43
+ \- \*\*Blazing fast\*\* - Groups by file size first
44
+
45
+ \- \*\*Progress bars\*\* - See what's happening
46
+
47
+ \- \*\*Beautiful output\*\* - Color-coded tables
48
+
49
+ \- \*\*Space calculator\*\* - Shows how much you'll save
50
+
51
+ \- \*\*Safe delete\*\* - Keeps first file, deletes rest
52
+
53
+
54
+
55
+ \## Installation
56
+
57
+
58
+
59
+ ```bash
60
+
61
+ pip install dupe-hunter
62
+
@@ -0,0 +1,11 @@
1
+ README.md
2
+ pyproject.toml
3
+ setup.py
4
+ src/__init__.py
5
+ src/dupe_hunter.py
6
+ src/dupe_hunter.egg-info/PKG-INFO
7
+ src/dupe_hunter.egg-info/SOURCES.txt
8
+ src/dupe_hunter.egg-info/dependency_links.txt
9
+ src/dupe_hunter.egg-info/entry_points.txt
10
+ src/dupe_hunter.egg-info/requires.txt
11
+ src/dupe_hunter.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ dupe-hunter = src.dupe_hunter:app
@@ -0,0 +1,3 @@
1
+ typer>=0.9.0
2
+ rich>=13.0.0
3
+ click>=8.0.0
@@ -0,0 +1,2 @@
1
+ __init__
2
+ dupe_hunter
@@ -0,0 +1,168 @@
1
+ import typer
2
+ from pathlib import Path
3
+ import hashlib
4
+ from rich.progress import track
5
+ from rich.console import Console
6
+ from rich.table import Table
7
+ from collections import defaultdict
8
+
9
+ # Fix for when running as installed package
10
+ import sys
11
+ sys.path.insert(0, str(Path(__file__).parent.parent))
12
+
13
+ app = typer.Typer()
14
+ console = Console()
15
+
16
+ def get_file_hash(filepath: Path):
17
+ hasher = hashlib.md5()
18
+ try:
19
+ with open(filepath, 'rb') as f:
20
+ for chunk in iter(lambda: f.read(8192), b''):
21
+ hasher.update(chunk)
22
+ return hasher.hexdigest()
23
+ except (PermissionError, OSError):
24
+ return None
25
+
26
+ @app.command()
27
+ def scan(
28
+ folder: str = typer.Argument(".", help="Folder to scan for duplicates"),
29
+ delete: bool = typer.Option(False, "--delete", help="Delete duplicate files (keeps the first one)")
30
+ ):
31
+ """Find duplicate files in a folder."""
32
+ console.print(f"[bold blue]📂 Scanning:[/bold blue] {folder}")
33
+
34
+ folder_path = Path(folder)
35
+ if not folder_path.exists():
36
+ console.print(f"[red]❌ Error:[/red] Folder '{folder}' doesn't exist!")
37
+ return
38
+
39
+ all_files = [f for f in folder_path.rglob("*") if f.is_file()]
40
+
41
+ if not all_files:
42
+ console.print("[yellow]⚠️ No files found![/yellow]")
43
+ return
44
+
45
+ console.print(f"Found [green]{len(all_files)}[/green] files")
46
+
47
+ size_groups = defaultdict(list)
48
+ for file in track(all_files, description="Grouping by size..."):
49
+ size_groups[file.stat().st_size].append(file)
50
+
51
+ potential_dupes = {
52
+ size: files
53
+ for size, files in size_groups.items()
54
+ if len(files) > 1
55
+ }
56
+
57
+ if not potential_dupes:
58
+ console.print("[green]✅ No duplicates found![/green]")
59
+ return
60
+
61
+ console.print(f"Found [yellow]{len(potential_dupes)}[/yellow] size groups")
62
+
63
+ duplicates = defaultdict(list)
64
+ for size, files in track(potential_dupes.items(), description="Hashing..."):
65
+ hash_groups = defaultdict(list)
66
+ for file in files:
67
+ file_hash = get_file_hash(file)
68
+ if file_hash:
69
+ hash_groups[file_hash].append(file)
70
+
71
+ for file_hash, dup_files in hash_groups.items():
72
+ if len(dup_files) > 1:
73
+ duplicates[file_hash] = dup_files
74
+
75
+ if not duplicates:
76
+ console.print("[green]✅ No exact duplicates found![/green]")
77
+ return
78
+
79
+ total_dupes = sum(len(files) for files in duplicates.values())
80
+ console.print(f"\n[bold red]🔍 Found {total_dupes} duplicates in {len(duplicates)} groups:\n")
81
+
82
+ for file_hash, files in duplicates.items():
83
+ table = Table(title=f"Hash: {file_hash[:8]}...")
84
+ table.add_column("File", style="cyan")
85
+ table.add_column("Size", style="green")
86
+
87
+ for f in files:
88
+ size_kb = f.stat().st_size / 1024
89
+ if size_kb > 1024:
90
+ size_mb = size_kb / 1024
91
+ table.add_row(str(f), f"{size_mb:.2f} MB")
92
+ else:
93
+ table.add_row(str(f), f"{size_kb:.2f} KB")
94
+
95
+ console.print(table)
96
+ console.print("─" * 50)
97
+
98
+ # ==============================================
99
+ # NEW: Calculate and display space savings
100
+ # ==============================================
101
+
102
+ # Calculate total space wasted
103
+ total_size = 0
104
+ total_savings = 0
105
+
106
+ for file_hash, files in duplicates.items():
107
+ # Size of all duplicate files in this group
108
+ group_size = sum(f.stat().st_size for f in files)
109
+ total_size += group_size
110
+
111
+ # Keep one copy, delete the rest
112
+ # So savings = group_size - size_of_one_file
113
+ group_savings = group_size - files[0].stat().st_size
114
+ total_savings += group_savings
115
+
116
+ # Display the savings
117
+ if total_savings > 0:
118
+ console.print("")
119
+ if total_savings > 1024 * 1024: # More than 1 MB
120
+ console.print(f"[bold yellow]💾 Potential space saved: {total_savings / (1024 * 1024):.2f} MB[/bold yellow]")
121
+ elif total_savings > 1024: # More than 1 KB
122
+ console.print(f"[bold yellow]💾 Potential space saved: {total_savings / 1024:.2f} KB[/bold yellow]")
123
+ else:
124
+ console.print(f"[bold yellow]💾 Potential space saved: {total_savings} bytes[/bold yellow]")
125
+
126
+ console.print(f"[bold cyan]📊 SUMMARY[/bold cyan]")
127
+ console.print(f" Total duplicate groups: [yellow]{len(duplicates)}[/yellow]")
128
+ console.print(f" Total duplicate files: [yellow]{total_dupes}[/yellow]")
129
+
130
+ if total_savings > 1024 * 1024:
131
+ console.print(f" Total space wasted: [yellow]{total_savings / (1024 * 1024):.2f} MB[/yellow]")
132
+ elif total_savings > 1024:
133
+ console.print(f" Total space wasted: [yellow]{total_savings / 1024:.2f} KB[/yellow]")
134
+ else:
135
+ console.print(f" Total space wasted: [yellow]{total_savings} bytes[/yellow]")
136
+
137
+ # ==============================================
138
+ # END OF NEW CODE
139
+ # ==============================================
140
+
141
+ # If delete flag is used, remove duplicates
142
+ if delete:
143
+ console.print("\n[bold yellow]⚠️ DELETE MODE ACTIVATED[/bold yellow]")
144
+ console.print("[yellow]Keeping the first file in each group, deleting the rest...[/yellow]")
145
+
146
+ deleted_count = 0
147
+ for file_hash, files in duplicates.items():
148
+ # Keep first file, delete the rest
149
+ for file in files[1:]:
150
+ try:
151
+ file.unlink()
152
+ console.print(f"[red]🗑️ Deleted:[/red] {file}")
153
+ deleted_count += 1
154
+ except Exception as e:
155
+ console.print(f"[red]❌ Error:[/red] {e}")
156
+
157
+ if deleted_count > 0:
158
+ console.print(f"\n[bold green]✅ Deleted {deleted_count} duplicate files![/bold green]")
159
+ console.print(f"[bold green]💾 Saved {total_savings / (1024 * 1024):.2f} MB of space![/bold green]")
160
+ else:
161
+ console.print("\n[yellow]No files were deleted.[/yellow]")
162
+
163
+ @app.command()
164
+ def hello(name: str = "World"):
165
+ console.print(f"[bold green]Hello {name}! 🚀[/bold green]")
166
+
167
+ if __name__ == "__main__":
168
+ app()