ilovecli 0.1.1__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.
- ilovecli-0.1.1/LICENSE +25 -0
- ilovecli-0.1.1/PKG-INFO +254 -0
- ilovecli-0.1.1/README.md +239 -0
- ilovecli-0.1.1/ilovecli/__init__.py +25 -0
- ilovecli-0.1.1/ilovecli/cli.py +141 -0
- ilovecli-0.1.1/ilovecli/image_tools.py +123 -0
- ilovecli-0.1.1/ilovecli/logger.py +8 -0
- ilovecli-0.1.1/ilovecli/pdf_tools.py +105 -0
- ilovecli-0.1.1/ilovecli/utils.py +10 -0
- ilovecli-0.1.1/ilovecli/video_tools.py +27 -0
- ilovecli-0.1.1/ilovecli.egg-info/PKG-INFO +254 -0
- ilovecli-0.1.1/ilovecli.egg-info/SOURCES.txt +16 -0
- ilovecli-0.1.1/ilovecli.egg-info/dependency_links.txt +1 -0
- ilovecli-0.1.1/ilovecli.egg-info/entry_points.txt +2 -0
- ilovecli-0.1.1/ilovecli.egg-info/requires.txt +4 -0
- ilovecli-0.1.1/ilovecli.egg-info/top_level.txt +1 -0
- ilovecli-0.1.1/pyproject.toml +24 -0
- ilovecli-0.1.1/setup.cfg +4 -0
ilovecli-0.1.1/LICENSE
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Deep Dhabal
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
<<<<<<< HEAD
|
|
22
|
+
SOFTWARE.
|
|
23
|
+
=======
|
|
24
|
+
SOFTWARE.
|
|
25
|
+
>>>>>>> 6722e1a0eb82323533fdaea2a1a3dedded46d53e
|
ilovecli-0.1.1/PKG-INFO
ADDED
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ilovecli
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: CLI tool to compress images, PDFs, and videos
|
|
5
|
+
Author: Deep Dhabal
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Requires-Python: >=3.8
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Dist: typer[all]
|
|
11
|
+
Requires-Dist: rich
|
|
12
|
+
Requires-Dist: pillow
|
|
13
|
+
Requires-Dist: tqdm
|
|
14
|
+
Dynamic: license-file
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# 🚀 ilovecli
|
|
20
|
+
|
|
21
|
+
> Compress smarter. From your terminal.
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
`ilovecli` is a fast, cross-platform command-line tool to compress **Images, PDFs, and Videos** directly from your terminal.
|
|
25
|
+
|
|
26
|
+
It supports smart auto-detection, target-size optimization, parallel processing, and Docker deployment.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## ✨ Features
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
- 🖼 Compress images (JPG, PNG, WEBP)
|
|
34
|
+
- 📄 Compress PDFs (Ghostscript powered)
|
|
35
|
+
- 🎬 Compress videos (FFmpeg powered)
|
|
36
|
+
- 🎯 Target-size compression (Images & PDFs)
|
|
37
|
+
- ⚡ Parallel folder image compression
|
|
38
|
+
- 📊 Original vs compressed size reporting
|
|
39
|
+
- 🐳 Docker support
|
|
40
|
+
- 📦 PyPI-ready package
|
|
41
|
+
- 🧠 Automatic file-type detection
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## 📦 Installation
|
|
46
|
+
|
|
47
|
+
### Install from PyPI
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pip install ilovecli
|
|
51
|
+
````
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
### Install from Source
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
git clone https://github.com/Dhabaldeep/ilovecli.git
|
|
59
|
+
cd ilovecli
|
|
60
|
+
pip install .
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## 🔧 System Requirements
|
|
66
|
+
|
|
67
|
+
Make sure the following are installed:
|
|
68
|
+
|
|
69
|
+
* Python 3.8+
|
|
70
|
+
* FFmpeg (for video compression)
|
|
71
|
+
* Ghostscript (for PDF compression)
|
|
72
|
+
|
|
73
|
+
Verify installation:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
ffmpeg -version
|
|
77
|
+
gs --version
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## 🚀 Usage
|
|
83
|
+
|
|
84
|
+
### 🔹 Compress Any Supported File
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
ilovecli compress file.jpg
|
|
88
|
+
ilovecli compress document.pdf
|
|
89
|
+
ilovecli compress video.mp4
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Automatic file-type detection included.
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
### 🎯 Compress to Target Size
|
|
97
|
+
|
|
98
|
+
#### Image
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
ilovecli target image.jpg 300
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Compresses image to approximately **300 KB** while maintaining best possible quality.
|
|
105
|
+
|
|
106
|
+
#### PDF
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
ilovecli target document.pdf 500
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Optimizes DPI dynamically to keep the file under **500 KB**.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
### 📄 Control PDF Compression Level
|
|
117
|
+
|
|
118
|
+
Available levels:
|
|
119
|
+
|
|
120
|
+
* `screen` (maximum compression)
|
|
121
|
+
* `ebook` (default)
|
|
122
|
+
* `printer`
|
|
123
|
+
* `prepress` (highest quality)
|
|
124
|
+
|
|
125
|
+
Example:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
ilovecli compress file.pdf --pdf-quality screen
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
### 🎬 Control Video Compression (CRF)
|
|
134
|
+
|
|
135
|
+
Lower CRF → Better quality
|
|
136
|
+
Higher CRF → Smaller file
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
ilovecli compress video.mp4 --crf 32
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Recommended range: **18–35**
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
### 📁 Compress All Images in Folder
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
ilovecli folder ./images
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Uses parallel processing for faster execution.
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
### 🔎 Show Version
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
ilovecli version
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## 🐳 Docker Support
|
|
165
|
+
|
|
166
|
+
### Build Docker Image
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
docker build -t ilovecli .
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
### Run Inside Container
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
docker run --rm -v $(pwd):/data ilovecli compress /data/file.pdf --pdf-quality screen
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
No need to manually install Python, FFmpeg, or Ghostscript.
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## 🏗 Project Structure
|
|
185
|
+
|
|
186
|
+
```
|
|
187
|
+
ilovecli/
|
|
188
|
+
│
|
|
189
|
+
├── cli.py
|
|
190
|
+
├── image_tools.py
|
|
191
|
+
├── pdf_tools.py
|
|
192
|
+
├── video_tools.py
|
|
193
|
+
├── utils.py
|
|
194
|
+
├── logger.py
|
|
195
|
+
└── __init__.py
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## 🛠 Tech Stack
|
|
201
|
+
|
|
202
|
+
* Python
|
|
203
|
+
* Typer (CLI framework)
|
|
204
|
+
* Pillow (Image processing)
|
|
205
|
+
* FFmpeg (Video compression)
|
|
206
|
+
* Ghostscript (PDF compression)
|
|
207
|
+
* Rich (Styled console output)
|
|
208
|
+
* TQDM (Progress bars)
|
|
209
|
+
* Multiprocessing
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## 📊 Example Output
|
|
214
|
+
|
|
215
|
+
```
|
|
216
|
+
Original: 10.4 MB
|
|
217
|
+
Compressed: 2.3 MB
|
|
218
|
+
Reduced: 77.8%
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## 💼 Resume Description
|
|
224
|
+
|
|
225
|
+
> Developed a cross-platform CLI-based media compression toolkit using Python, Typer, multiprocessing, FFmpeg, and Ghostscript. Implemented dynamic target-size optimization via binary search, parallel processing, structured logging, and Docker containerization. Packaged for PyPI and Docker deployment.
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## 📄 License
|
|
230
|
+
|
|
231
|
+
MIT License
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## 🤝 Contributing
|
|
236
|
+
|
|
237
|
+
Contributions are welcome!
|
|
238
|
+
|
|
239
|
+
1. Fork the repository
|
|
240
|
+
2. Create your feature branch
|
|
241
|
+
3. Commit changes
|
|
242
|
+
4. Open a pull request
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## ⭐ Support
|
|
247
|
+
|
|
248
|
+
If you find this project useful:
|
|
249
|
+
|
|
250
|
+
* ⭐ Star the repository
|
|
251
|
+
* 🐛 Report issues
|
|
252
|
+
* 🚀 Share with others
|
|
253
|
+
|
|
254
|
+
```
|
ilovecli-0.1.1/README.md
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
# 🚀 ilovecli
|
|
5
|
+
|
|
6
|
+
> Compress smarter. From your terminal.
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
`ilovecli` is a fast, cross-platform command-line tool to compress **Images, PDFs, and Videos** directly from your terminal.
|
|
10
|
+
|
|
11
|
+
It supports smart auto-detection, target-size optimization, parallel processing, and Docker deployment.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## ✨ Features
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
- 🖼 Compress images (JPG, PNG, WEBP)
|
|
19
|
+
- 📄 Compress PDFs (Ghostscript powered)
|
|
20
|
+
- 🎬 Compress videos (FFmpeg powered)
|
|
21
|
+
- 🎯 Target-size compression (Images & PDFs)
|
|
22
|
+
- ⚡ Parallel folder image compression
|
|
23
|
+
- 📊 Original vs compressed size reporting
|
|
24
|
+
- 🐳 Docker support
|
|
25
|
+
- 📦 PyPI-ready package
|
|
26
|
+
- 🧠 Automatic file-type detection
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## 📦 Installation
|
|
31
|
+
|
|
32
|
+
### Install from PyPI
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install ilovecli
|
|
36
|
+
````
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
### Install from Source
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
git clone https://github.com/Dhabaldeep/ilovecli.git
|
|
44
|
+
cd ilovecli
|
|
45
|
+
pip install .
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## 🔧 System Requirements
|
|
51
|
+
|
|
52
|
+
Make sure the following are installed:
|
|
53
|
+
|
|
54
|
+
* Python 3.8+
|
|
55
|
+
* FFmpeg (for video compression)
|
|
56
|
+
* Ghostscript (for PDF compression)
|
|
57
|
+
|
|
58
|
+
Verify installation:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
ffmpeg -version
|
|
62
|
+
gs --version
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## 🚀 Usage
|
|
68
|
+
|
|
69
|
+
### 🔹 Compress Any Supported File
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
ilovecli compress file.jpg
|
|
73
|
+
ilovecli compress document.pdf
|
|
74
|
+
ilovecli compress video.mp4
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Automatic file-type detection included.
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
### 🎯 Compress to Target Size
|
|
82
|
+
|
|
83
|
+
#### Image
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
ilovecli target image.jpg 300
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Compresses image to approximately **300 KB** while maintaining best possible quality.
|
|
90
|
+
|
|
91
|
+
#### PDF
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
ilovecli target document.pdf 500
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Optimizes DPI dynamically to keep the file under **500 KB**.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
### 📄 Control PDF Compression Level
|
|
102
|
+
|
|
103
|
+
Available levels:
|
|
104
|
+
|
|
105
|
+
* `screen` (maximum compression)
|
|
106
|
+
* `ebook` (default)
|
|
107
|
+
* `printer`
|
|
108
|
+
* `prepress` (highest quality)
|
|
109
|
+
|
|
110
|
+
Example:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
ilovecli compress file.pdf --pdf-quality screen
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
### 🎬 Control Video Compression (CRF)
|
|
119
|
+
|
|
120
|
+
Lower CRF → Better quality
|
|
121
|
+
Higher CRF → Smaller file
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
ilovecli compress video.mp4 --crf 32
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Recommended range: **18–35**
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
### 📁 Compress All Images in Folder
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
ilovecli folder ./images
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Uses parallel processing for faster execution.
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
### 🔎 Show Version
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
ilovecli version
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## 🐳 Docker Support
|
|
150
|
+
|
|
151
|
+
### Build Docker Image
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
docker build -t ilovecli .
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
### Run Inside Container
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
docker run --rm -v $(pwd):/data ilovecli compress /data/file.pdf --pdf-quality screen
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
No need to manually install Python, FFmpeg, or Ghostscript.
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## 🏗 Project Structure
|
|
170
|
+
|
|
171
|
+
```
|
|
172
|
+
ilovecli/
|
|
173
|
+
│
|
|
174
|
+
├── cli.py
|
|
175
|
+
├── image_tools.py
|
|
176
|
+
├── pdf_tools.py
|
|
177
|
+
├── video_tools.py
|
|
178
|
+
├── utils.py
|
|
179
|
+
├── logger.py
|
|
180
|
+
└── __init__.py
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## 🛠 Tech Stack
|
|
186
|
+
|
|
187
|
+
* Python
|
|
188
|
+
* Typer (CLI framework)
|
|
189
|
+
* Pillow (Image processing)
|
|
190
|
+
* FFmpeg (Video compression)
|
|
191
|
+
* Ghostscript (PDF compression)
|
|
192
|
+
* Rich (Styled console output)
|
|
193
|
+
* TQDM (Progress bars)
|
|
194
|
+
* Multiprocessing
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## 📊 Example Output
|
|
199
|
+
|
|
200
|
+
```
|
|
201
|
+
Original: 10.4 MB
|
|
202
|
+
Compressed: 2.3 MB
|
|
203
|
+
Reduced: 77.8%
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## 💼 Resume Description
|
|
209
|
+
|
|
210
|
+
> Developed a cross-platform CLI-based media compression toolkit using Python, Typer, multiprocessing, FFmpeg, and Ghostscript. Implemented dynamic target-size optimization via binary search, parallel processing, structured logging, and Docker containerization. Packaged for PyPI and Docker deployment.
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## 📄 License
|
|
215
|
+
|
|
216
|
+
MIT License
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## 🤝 Contributing
|
|
221
|
+
|
|
222
|
+
Contributions are welcome!
|
|
223
|
+
|
|
224
|
+
1. Fork the repository
|
|
225
|
+
2. Create your feature branch
|
|
226
|
+
3. Commit changes
|
|
227
|
+
4. Open a pull request
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## ⭐ Support
|
|
232
|
+
|
|
233
|
+
If you find this project useful:
|
|
234
|
+
|
|
235
|
+
* ⭐ Star the repository
|
|
236
|
+
* 🐛 Report issues
|
|
237
|
+
* 🚀 Share with others
|
|
238
|
+
|
|
239
|
+
```
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from .image_tools import (
|
|
2
|
+
compress_image,
|
|
3
|
+
compress_folder_parallel,
|
|
4
|
+
convert_image,
|
|
5
|
+
compress_to_target_size,
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
from .pdf_tools import (
|
|
9
|
+
compress_pdf,
|
|
10
|
+
compress_pdf_to_target_size,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
from .video_tools import compress_video
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"compress_image",
|
|
17
|
+
"compress_folder_parallel",
|
|
18
|
+
"convert_image",
|
|
19
|
+
"compress_to_target_size",
|
|
20
|
+
"compress_pdf",
|
|
21
|
+
"compress_pdf_to_target_size",
|
|
22
|
+
"compress_video",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
__version__ = "0.3.0"
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
from ilovecli import compress_pdf_to_target_size
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from rich.console import Console
|
|
5
|
+
from ilovecli import (
|
|
6
|
+
compress_image,
|
|
7
|
+
compress_folder_parallel,
|
|
8
|
+
compress_pdf,
|
|
9
|
+
compress_video,
|
|
10
|
+
convert_image,
|
|
11
|
+
compress_to_target_size,
|
|
12
|
+
__version__,
|
|
13
|
+
)
|
|
14
|
+
from ilovecli.logger import logger
|
|
15
|
+
|
|
16
|
+
app = typer.Typer(help="🚀 ilovecli - Image, PDF & Video Compressor")
|
|
17
|
+
console = Console()
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@app.command()
|
|
21
|
+
def compress(
|
|
22
|
+
file: Path,
|
|
23
|
+
quality: int = typer.Option(60, help="Image quality (10-95)"),
|
|
24
|
+
pdf_quality: str = typer.Option(
|
|
25
|
+
"ebook",
|
|
26
|
+
help="PDF quality: screen, ebook, printer, prepress",
|
|
27
|
+
case_sensitive=False,
|
|
28
|
+
show_choices=True,
|
|
29
|
+
),
|
|
30
|
+
crf: int = typer.Option(28, help="Video CRF (18-35)")
|
|
31
|
+
):
|
|
32
|
+
"""
|
|
33
|
+
Auto-detect and compress file
|
|
34
|
+
"""
|
|
35
|
+
if not file.exists():
|
|
36
|
+
logger.error("File not found")
|
|
37
|
+
console.print("❌ File not found", style="red")
|
|
38
|
+
raise typer.Exit()
|
|
39
|
+
|
|
40
|
+
ext = file.suffix.lower()
|
|
41
|
+
|
|
42
|
+
try:
|
|
43
|
+
logger.info(f"Starting compression for {file.name}")
|
|
44
|
+
|
|
45
|
+
if ext in [".jpg", ".jpeg", ".png", ".webp"]:
|
|
46
|
+
compress_image(str(file), quality)
|
|
47
|
+
|
|
48
|
+
elif ext == ".pdf":
|
|
49
|
+
compress_pdf(str(file), pdf_quality)
|
|
50
|
+
|
|
51
|
+
elif ext in [".mp4", ".mkv", ".mov"]:
|
|
52
|
+
compress_video(str(file),crf)
|
|
53
|
+
|
|
54
|
+
else:
|
|
55
|
+
logger.warning("Unsupported file type")
|
|
56
|
+
console.print("❌ Unsupported file type", style="red")
|
|
57
|
+
raise typer.Exit()
|
|
58
|
+
|
|
59
|
+
logger.info("Compression completed successfully")
|
|
60
|
+
|
|
61
|
+
except Exception as e:
|
|
62
|
+
logger.exception("Unexpected error during compression")
|
|
63
|
+
console.print(f"❌ Error: {e}", style="red")
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@app.command()
|
|
67
|
+
def folder(
|
|
68
|
+
path: Path,
|
|
69
|
+
quality: int = typer.Option(60, help="Image quality (10-95)")
|
|
70
|
+
):
|
|
71
|
+
"""
|
|
72
|
+
Compress all images inside folder using parallel processing
|
|
73
|
+
"""
|
|
74
|
+
if not path.exists():
|
|
75
|
+
logger.error("Folder not found")
|
|
76
|
+
console.print("❌ Folder not found", style="red")
|
|
77
|
+
raise typer.Exit()
|
|
78
|
+
|
|
79
|
+
logger.info(f"Starting folder compression: {path}")
|
|
80
|
+
compress_folder_parallel(str(path), quality)
|
|
81
|
+
logger.info("Folder compression complete")
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
@app.command()
|
|
85
|
+
def convert(input: Path, output: Path):
|
|
86
|
+
"""
|
|
87
|
+
Convert image format
|
|
88
|
+
"""
|
|
89
|
+
logger.info(f"Converting {input.name} to {output.name}")
|
|
90
|
+
convert_image(str(input), str(output))
|
|
91
|
+
logger.info("Conversion complete")
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
@app.command()
|
|
95
|
+
def target(
|
|
96
|
+
file: Path,
|
|
97
|
+
size_kb: int = typer.Argument(..., help="Target size in KB"),
|
|
98
|
+
):
|
|
99
|
+
"""
|
|
100
|
+
Compress file to target size in KB
|
|
101
|
+
Works for images and PDFs
|
|
102
|
+
Example:
|
|
103
|
+
ilovecli target image.jpg 300
|
|
104
|
+
ilovecli target file.pdf 500
|
|
105
|
+
"""
|
|
106
|
+
if not file.exists():
|
|
107
|
+
logger.error("File not found for target compression")
|
|
108
|
+
console.print("❌ File not found", style="red")
|
|
109
|
+
raise typer.Exit()
|
|
110
|
+
|
|
111
|
+
ext = file.suffix.lower()
|
|
112
|
+
|
|
113
|
+
logger.info(f"Starting target compression for {file.name} to {size_kb} KB")
|
|
114
|
+
|
|
115
|
+
try:
|
|
116
|
+
if ext in [".jpg", ".jpeg", ".png", ".webp"]:
|
|
117
|
+
compress_to_target_size(str(file), size_kb)
|
|
118
|
+
|
|
119
|
+
elif ext == ".pdf":
|
|
120
|
+
from ilovecli import compress_pdf_to_target_size
|
|
121
|
+
compress_pdf_to_target_size(str(file), size_kb)
|
|
122
|
+
|
|
123
|
+
else:
|
|
124
|
+
logger.warning("Target compression not supported for this file type")
|
|
125
|
+
console.print("❌ Target compression only supported for images and PDFs", style="red")
|
|
126
|
+
raise typer.Exit()
|
|
127
|
+
|
|
128
|
+
logger.info("Target compression completed successfully")
|
|
129
|
+
|
|
130
|
+
except Exception:
|
|
131
|
+
logger.exception("Error during target compression")
|
|
132
|
+
console.print("❌ Target compression failed", style="red")
|
|
133
|
+
|
|
134
|
+
@app.command()
|
|
135
|
+
def version():
|
|
136
|
+
logger.info("Version command called")
|
|
137
|
+
console.print(f"ilovecli version {__version__}")
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
if __name__ == "__main__":
|
|
141
|
+
app()
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
from PIL import Image
|
|
2
|
+
from multiprocessing import Pool, cpu_count
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
from .logger import logger
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def compress_image(input_path: str, quality: int = 60):
|
|
10
|
+
try:
|
|
11
|
+
input_path = Path(input_path)
|
|
12
|
+
output = input_path.parent / f"compressed_{input_path.name}"
|
|
13
|
+
|
|
14
|
+
original_size = input_path.stat().st_size
|
|
15
|
+
|
|
16
|
+
img = Image.open(input_path)
|
|
17
|
+
|
|
18
|
+
if img.format in ["JPEG", "JPG"]:
|
|
19
|
+
img.save(output, quality=quality, optimize=True)
|
|
20
|
+
elif img.format == "PNG":
|
|
21
|
+
img.save(output, optimize=True)
|
|
22
|
+
else:
|
|
23
|
+
img.save(output)
|
|
24
|
+
|
|
25
|
+
new_size = output.stat().st_size
|
|
26
|
+
reduction = ((original_size - new_size) / original_size) * 100
|
|
27
|
+
|
|
28
|
+
logger.info(
|
|
29
|
+
f"Image compressed: {output.name} | "
|
|
30
|
+
f"Reduced {reduction:.2f}%"
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
except Exception:
|
|
34
|
+
logger.exception("Image compression failed")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def convert_image(input_path: str, output_path: str):
|
|
38
|
+
try:
|
|
39
|
+
img = Image.open(input_path)
|
|
40
|
+
img.save(output_path)
|
|
41
|
+
logger.info(f"Image converted: {output_path}")
|
|
42
|
+
except Exception:
|
|
43
|
+
logger.exception("Image conversion failed")
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _compress_single(args):
|
|
47
|
+
input_path, quality, output_folder = args
|
|
48
|
+
input_path = Path(input_path)
|
|
49
|
+
output_path = Path(output_folder) / f"compressed_{input_path.name}"
|
|
50
|
+
|
|
51
|
+
try:
|
|
52
|
+
img = Image.open(input_path)
|
|
53
|
+
img.save(output_path, quality=quality, optimize=True)
|
|
54
|
+
return input_path.name
|
|
55
|
+
except Exception:
|
|
56
|
+
logger.exception(f"Failed compressing {input_path.name}")
|
|
57
|
+
return None
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def compress_folder_parallel(folder_path: str, quality: int = 60):
|
|
61
|
+
folder = Path(folder_path)
|
|
62
|
+
|
|
63
|
+
files = list(folder.glob("*.[jJ][pP][gG]")) + \
|
|
64
|
+
list(folder.glob("*.[jJ][pP][eE][gG]")) + \
|
|
65
|
+
list(folder.glob("*.[pP][nN][gG]")) + \
|
|
66
|
+
list(folder.glob("*.[wW][eE][bB][pP]"))
|
|
67
|
+
|
|
68
|
+
if not files:
|
|
69
|
+
logger.warning("No supported images found in folder")
|
|
70
|
+
return
|
|
71
|
+
|
|
72
|
+
output_folder = folder / "compressed_output"
|
|
73
|
+
output_folder.mkdir(exist_ok=True)
|
|
74
|
+
|
|
75
|
+
tasks = [(str(file), quality, str(output_folder)) for file in files]
|
|
76
|
+
|
|
77
|
+
workers = min(cpu_count(), len(tasks))
|
|
78
|
+
logger.info(f"Using {workers} CPU cores for parallel compression")
|
|
79
|
+
|
|
80
|
+
with Pool(workers) as pool:
|
|
81
|
+
for _ in pool.imap_unordered(_compress_single, tasks):
|
|
82
|
+
pass
|
|
83
|
+
|
|
84
|
+
logger.info("Parallel folder compression completed")
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def compress_to_target_size(input_path: str, target_kb: int):
|
|
88
|
+
try:
|
|
89
|
+
input_path = Path(input_path)
|
|
90
|
+
output = input_path.parent / f"target_{input_path.name}"
|
|
91
|
+
|
|
92
|
+
target_bytes = target_kb * 1024
|
|
93
|
+
img = Image.open(input_path).convert("RGB")
|
|
94
|
+
|
|
95
|
+
low, high = 5, 95
|
|
96
|
+
best_quality = None
|
|
97
|
+
|
|
98
|
+
while low <= high:
|
|
99
|
+
mid = (low + high) // 2
|
|
100
|
+
img.save(output, format="JPEG", quality=mid, optimize=True)
|
|
101
|
+
size = output.stat().st_size
|
|
102
|
+
|
|
103
|
+
if size > target_bytes:
|
|
104
|
+
high = mid - 1
|
|
105
|
+
else:
|
|
106
|
+
best_quality = mid
|
|
107
|
+
low = mid + 1
|
|
108
|
+
|
|
109
|
+
if best_quality is None:
|
|
110
|
+
logger.error("Could not compress to desired size")
|
|
111
|
+
return
|
|
112
|
+
|
|
113
|
+
img.save(output, format="JPEG", quality=best_quality, optimize=True)
|
|
114
|
+
|
|
115
|
+
final_size_kb = output.stat().st_size / 1024
|
|
116
|
+
logger.info(
|
|
117
|
+
f"Target compression complete: {output.name} | "
|
|
118
|
+
f"Final size: {final_size_kb:.2f} KB | "
|
|
119
|
+
f"Quality used: {best_quality}"
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
except Exception:
|
|
123
|
+
logger.exception("Target size compression failed")
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
#pdf_tools.py
|
|
2
|
+
import subprocess
|
|
3
|
+
from rich.console import Console
|
|
4
|
+
from tqdm import tqdm
|
|
5
|
+
import os
|
|
6
|
+
from .utils import print_size_report
|
|
7
|
+
|
|
8
|
+
console = Console()
|
|
9
|
+
|
|
10
|
+
def compress_pdf(input_path: str, quality: str = "ebook"):
|
|
11
|
+
import os
|
|
12
|
+
import subprocess
|
|
13
|
+
|
|
14
|
+
output = "compressed_" + os.path.basename(input_path)
|
|
15
|
+
|
|
16
|
+
original_size = os.path.getsize(input_path)
|
|
17
|
+
|
|
18
|
+
result = subprocess.run([
|
|
19
|
+
"gs",
|
|
20
|
+
"-sDEVICE=pdfwrite",
|
|
21
|
+
"-dCompatibilityLevel=1.4",
|
|
22
|
+
f"-dPDFSETTINGS=/{quality}",
|
|
23
|
+
"-dNOPAUSE",
|
|
24
|
+
"-dQUIET",
|
|
25
|
+
"-dBATCH",
|
|
26
|
+
f"-sOutputFile={output}",
|
|
27
|
+
input_path
|
|
28
|
+
])
|
|
29
|
+
|
|
30
|
+
if result.returncode != 0:
|
|
31
|
+
print("❌ Ghostscript failed")
|
|
32
|
+
return
|
|
33
|
+
|
|
34
|
+
new_size = os.path.getsize(output)
|
|
35
|
+
|
|
36
|
+
print_size_report(original_size, new_size)
|
|
37
|
+
|
|
38
|
+
def compress_pdf_to_target_size(input_path: str, target_kb: int):
|
|
39
|
+
import os
|
|
40
|
+
import subprocess
|
|
41
|
+
|
|
42
|
+
target_bytes = target_kb * 1024
|
|
43
|
+
output = "target_" + os.path.basename(input_path)
|
|
44
|
+
|
|
45
|
+
original_size = os.path.getsize(input_path)
|
|
46
|
+
|
|
47
|
+
low = 50 # minimum DPI
|
|
48
|
+
high = 300 # maximum DPI
|
|
49
|
+
best_dpi = None
|
|
50
|
+
|
|
51
|
+
while low <= high:
|
|
52
|
+
mid = (low + high) // 2
|
|
53
|
+
|
|
54
|
+
subprocess.run([
|
|
55
|
+
"gs",
|
|
56
|
+
"-sDEVICE=pdfwrite",
|
|
57
|
+
"-dCompatibilityLevel=1.4",
|
|
58
|
+
"-dDownsampleColorImages=true",
|
|
59
|
+
"-dColorImageResolution=" + str(mid),
|
|
60
|
+
"-dDownsampleGrayImages=true",
|
|
61
|
+
"-dGrayImageResolution=" + str(mid),
|
|
62
|
+
"-dDownsampleMonoImages=true",
|
|
63
|
+
"-dMonoImageResolution=" + str(mid),
|
|
64
|
+
"-dNOPAUSE",
|
|
65
|
+
"-dQUIET",
|
|
66
|
+
"-dBATCH",
|
|
67
|
+
"-sOutputFile=" + output,
|
|
68
|
+
input_path
|
|
69
|
+
], check=True)
|
|
70
|
+
|
|
71
|
+
new_size = os.path.getsize(output)
|
|
72
|
+
|
|
73
|
+
if new_size > target_bytes:
|
|
74
|
+
high = mid - 1
|
|
75
|
+
else:
|
|
76
|
+
best_dpi = mid
|
|
77
|
+
low = mid + 1
|
|
78
|
+
|
|
79
|
+
if best_dpi is None:
|
|
80
|
+
print("❌ Could not reach target size")
|
|
81
|
+
return
|
|
82
|
+
|
|
83
|
+
# Final save using best DPI
|
|
84
|
+
subprocess.run([
|
|
85
|
+
"gs",
|
|
86
|
+
"-sDEVICE=pdfwrite",
|
|
87
|
+
"-dCompatibilityLevel=1.4",
|
|
88
|
+
"-dDownsampleColorImages=true",
|
|
89
|
+
"-dColorImageResolution=" + str(best_dpi),
|
|
90
|
+
"-dDownsampleGrayImages=true",
|
|
91
|
+
"-dGrayImageResolution=" + str(best_dpi),
|
|
92
|
+
"-dDownsampleMonoImages=true",
|
|
93
|
+
"-dMonoImageResolution=" + str(best_dpi),
|
|
94
|
+
"-dNOPAUSE",
|
|
95
|
+
"-dQUIET",
|
|
96
|
+
"-dBATCH",
|
|
97
|
+
"-sOutputFile=" + output,
|
|
98
|
+
input_path
|
|
99
|
+
], check=True)
|
|
100
|
+
|
|
101
|
+
final_size_kb = round(os.path.getsize(output) / 1024, 2)
|
|
102
|
+
|
|
103
|
+
print(f"✅ Saved as {output}")
|
|
104
|
+
print(f"📦 Final Size: {final_size_kb} KB")
|
|
105
|
+
print(f"🎯 DPI Used: {best_dpi}")
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# utils.py
|
|
2
|
+
def print_size_report(original, new):
|
|
3
|
+
original_mb = original / (1024 * 1024)
|
|
4
|
+
new_mb = new / (1024 * 1024)
|
|
5
|
+
|
|
6
|
+
reduction = ((original - new) / original) * 100
|
|
7
|
+
|
|
8
|
+
print(f"Original: {round(original_mb,2)} MB")
|
|
9
|
+
print(f"Compressed: {round(new_mb,2)} MB")
|
|
10
|
+
print(f"Reduced: {round(reduction,2)}%")
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# video_tools.py
|
|
2
|
+
import subprocess
|
|
3
|
+
from rich.console import Console
|
|
4
|
+
from tqdm import tqdm
|
|
5
|
+
import os
|
|
6
|
+
|
|
7
|
+
console = Console()
|
|
8
|
+
|
|
9
|
+
def compress_video(input_path: str, crf: int = 28):
|
|
10
|
+
output = "compressed_" + os.path.basename(input_path)
|
|
11
|
+
|
|
12
|
+
try:
|
|
13
|
+
subprocess.run([
|
|
14
|
+
"ffmpeg",
|
|
15
|
+
"-i", input_path,
|
|
16
|
+
"-vcodec", "libx264",
|
|
17
|
+
"-crf", str(crf),
|
|
18
|
+
"-preset", "slow", # better compression
|
|
19
|
+
"-movflags", "+faststart", # better for web streaming
|
|
20
|
+
"-y",
|
|
21
|
+
output
|
|
22
|
+
], check=True)
|
|
23
|
+
|
|
24
|
+
console.print(f"✅ Saved as {output}", style="green")
|
|
25
|
+
|
|
26
|
+
except subprocess.CalledProcessError:
|
|
27
|
+
console.print("❌ FFmpeg failed", style="red")
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ilovecli
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: CLI tool to compress images, PDFs, and videos
|
|
5
|
+
Author: Deep Dhabal
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Requires-Python: >=3.8
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Dist: typer[all]
|
|
11
|
+
Requires-Dist: rich
|
|
12
|
+
Requires-Dist: pillow
|
|
13
|
+
Requires-Dist: tqdm
|
|
14
|
+
Dynamic: license-file
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# 🚀 ilovecli
|
|
20
|
+
|
|
21
|
+
> Compress smarter. From your terminal.
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
`ilovecli` is a fast, cross-platform command-line tool to compress **Images, PDFs, and Videos** directly from your terminal.
|
|
25
|
+
|
|
26
|
+
It supports smart auto-detection, target-size optimization, parallel processing, and Docker deployment.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## ✨ Features
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
- 🖼 Compress images (JPG, PNG, WEBP)
|
|
34
|
+
- 📄 Compress PDFs (Ghostscript powered)
|
|
35
|
+
- 🎬 Compress videos (FFmpeg powered)
|
|
36
|
+
- 🎯 Target-size compression (Images & PDFs)
|
|
37
|
+
- ⚡ Parallel folder image compression
|
|
38
|
+
- 📊 Original vs compressed size reporting
|
|
39
|
+
- 🐳 Docker support
|
|
40
|
+
- 📦 PyPI-ready package
|
|
41
|
+
- 🧠 Automatic file-type detection
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## 📦 Installation
|
|
46
|
+
|
|
47
|
+
### Install from PyPI
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pip install ilovecli
|
|
51
|
+
````
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
### Install from Source
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
git clone https://github.com/Dhabaldeep/ilovecli.git
|
|
59
|
+
cd ilovecli
|
|
60
|
+
pip install .
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## 🔧 System Requirements
|
|
66
|
+
|
|
67
|
+
Make sure the following are installed:
|
|
68
|
+
|
|
69
|
+
* Python 3.8+
|
|
70
|
+
* FFmpeg (for video compression)
|
|
71
|
+
* Ghostscript (for PDF compression)
|
|
72
|
+
|
|
73
|
+
Verify installation:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
ffmpeg -version
|
|
77
|
+
gs --version
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## 🚀 Usage
|
|
83
|
+
|
|
84
|
+
### 🔹 Compress Any Supported File
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
ilovecli compress file.jpg
|
|
88
|
+
ilovecli compress document.pdf
|
|
89
|
+
ilovecli compress video.mp4
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Automatic file-type detection included.
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
### 🎯 Compress to Target Size
|
|
97
|
+
|
|
98
|
+
#### Image
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
ilovecli target image.jpg 300
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Compresses image to approximately **300 KB** while maintaining best possible quality.
|
|
105
|
+
|
|
106
|
+
#### PDF
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
ilovecli target document.pdf 500
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Optimizes DPI dynamically to keep the file under **500 KB**.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
### 📄 Control PDF Compression Level
|
|
117
|
+
|
|
118
|
+
Available levels:
|
|
119
|
+
|
|
120
|
+
* `screen` (maximum compression)
|
|
121
|
+
* `ebook` (default)
|
|
122
|
+
* `printer`
|
|
123
|
+
* `prepress` (highest quality)
|
|
124
|
+
|
|
125
|
+
Example:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
ilovecli compress file.pdf --pdf-quality screen
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
### 🎬 Control Video Compression (CRF)
|
|
134
|
+
|
|
135
|
+
Lower CRF → Better quality
|
|
136
|
+
Higher CRF → Smaller file
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
ilovecli compress video.mp4 --crf 32
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Recommended range: **18–35**
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
### 📁 Compress All Images in Folder
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
ilovecli folder ./images
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Uses parallel processing for faster execution.
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
### 🔎 Show Version
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
ilovecli version
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## 🐳 Docker Support
|
|
165
|
+
|
|
166
|
+
### Build Docker Image
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
docker build -t ilovecli .
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
### Run Inside Container
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
docker run --rm -v $(pwd):/data ilovecli compress /data/file.pdf --pdf-quality screen
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
No need to manually install Python, FFmpeg, or Ghostscript.
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## 🏗 Project Structure
|
|
185
|
+
|
|
186
|
+
```
|
|
187
|
+
ilovecli/
|
|
188
|
+
│
|
|
189
|
+
├── cli.py
|
|
190
|
+
├── image_tools.py
|
|
191
|
+
├── pdf_tools.py
|
|
192
|
+
├── video_tools.py
|
|
193
|
+
├── utils.py
|
|
194
|
+
├── logger.py
|
|
195
|
+
└── __init__.py
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## 🛠 Tech Stack
|
|
201
|
+
|
|
202
|
+
* Python
|
|
203
|
+
* Typer (CLI framework)
|
|
204
|
+
* Pillow (Image processing)
|
|
205
|
+
* FFmpeg (Video compression)
|
|
206
|
+
* Ghostscript (PDF compression)
|
|
207
|
+
* Rich (Styled console output)
|
|
208
|
+
* TQDM (Progress bars)
|
|
209
|
+
* Multiprocessing
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## 📊 Example Output
|
|
214
|
+
|
|
215
|
+
```
|
|
216
|
+
Original: 10.4 MB
|
|
217
|
+
Compressed: 2.3 MB
|
|
218
|
+
Reduced: 77.8%
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## 💼 Resume Description
|
|
224
|
+
|
|
225
|
+
> Developed a cross-platform CLI-based media compression toolkit using Python, Typer, multiprocessing, FFmpeg, and Ghostscript. Implemented dynamic target-size optimization via binary search, parallel processing, structured logging, and Docker containerization. Packaged for PyPI and Docker deployment.
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## 📄 License
|
|
230
|
+
|
|
231
|
+
MIT License
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## 🤝 Contributing
|
|
236
|
+
|
|
237
|
+
Contributions are welcome!
|
|
238
|
+
|
|
239
|
+
1. Fork the repository
|
|
240
|
+
2. Create your feature branch
|
|
241
|
+
3. Commit changes
|
|
242
|
+
4. Open a pull request
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## ⭐ Support
|
|
247
|
+
|
|
248
|
+
If you find this project useful:
|
|
249
|
+
|
|
250
|
+
* ⭐ Star the repository
|
|
251
|
+
* 🐛 Report issues
|
|
252
|
+
* 🚀 Share with others
|
|
253
|
+
|
|
254
|
+
```
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
ilovecli/__init__.py
|
|
5
|
+
ilovecli/cli.py
|
|
6
|
+
ilovecli/image_tools.py
|
|
7
|
+
ilovecli/logger.py
|
|
8
|
+
ilovecli/pdf_tools.py
|
|
9
|
+
ilovecli/utils.py
|
|
10
|
+
ilovecli/video_tools.py
|
|
11
|
+
ilovecli.egg-info/PKG-INFO
|
|
12
|
+
ilovecli.egg-info/SOURCES.txt
|
|
13
|
+
ilovecli.egg-info/dependency_links.txt
|
|
14
|
+
ilovecli.egg-info/entry_points.txt
|
|
15
|
+
ilovecli.egg-info/requires.txt
|
|
16
|
+
ilovecli.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ilovecli
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "ilovecli"
|
|
3
|
+
version = "0.1.1"
|
|
4
|
+
description = "CLI tool to compress images, PDFs, and videos"
|
|
5
|
+
authors = [
|
|
6
|
+
{ name = "Deep Dhabal" }
|
|
7
|
+
]
|
|
8
|
+
readme = "README.md"
|
|
9
|
+
license = "MIT"
|
|
10
|
+
requires-python = ">=3.8"
|
|
11
|
+
|
|
12
|
+
dependencies = [
|
|
13
|
+
"typer[all]",
|
|
14
|
+
"rich",
|
|
15
|
+
"pillow",
|
|
16
|
+
"tqdm"
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
[project.scripts]
|
|
20
|
+
ilovecli = "ilovecli.cli:app"
|
|
21
|
+
|
|
22
|
+
[build-system]
|
|
23
|
+
requires = ["setuptools>=61.0"]
|
|
24
|
+
build-backend = "setuptools.build_meta"
|
ilovecli-0.1.1/setup.cfg
ADDED