boosty-milker 1.0.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.
- boosty_milker-1.0.1/PKG-INFO +105 -0
- boosty_milker-1.0.1/README.md +94 -0
- boosty_milker-1.0.1/boosty_milker/__init__.py +1 -0
- boosty_milker-1.0.1/boosty_milker/main.py +225 -0
- boosty_milker-1.0.1/boosty_milker.egg-info/PKG-INFO +105 -0
- boosty_milker-1.0.1/boosty_milker.egg-info/SOURCES.txt +10 -0
- boosty_milker-1.0.1/boosty_milker.egg-info/dependency_links.txt +1 -0
- boosty_milker-1.0.1/boosty_milker.egg-info/entry_points.txt +2 -0
- boosty_milker-1.0.1/boosty_milker.egg-info/requires.txt +3 -0
- boosty_milker-1.0.1/boosty_milker.egg-info/top_level.txt +1 -0
- boosty_milker-1.0.1/pyproject.toml +22 -0
- boosty_milker-1.0.1/setup.cfg +4 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: boosty-milker
|
|
3
|
+
Version: 1.0.1
|
|
4
|
+
Summary: CLI tool to download photos from Boosty.to
|
|
5
|
+
Author-email: F3T1W <f3t1w@icloud.com>
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: aiohttp>=3.8.0
|
|
9
|
+
Requires-Dist: tqdm>=4.65.0
|
|
10
|
+
Requires-Dist: colorama>=0.4.6
|
|
11
|
+
|
|
12
|
+
# Boosty Milker 🥛
|
|
13
|
+
|
|
14
|
+
[](https://github.com/F3T1W/BoostyMilker/releases)
|
|
15
|
+
[](https://pypi.org/project/boosty-milker/)
|
|
16
|
+
[](https://community.chocolatey.org/packages/boosty-milker)
|
|
17
|
+
[](https://github.com/F3T1W/homebrew-tap)
|
|
18
|
+
[](https://github.com/F3T1W/apt-repo)
|
|
19
|
+
|
|
20
|
+
**Boosty Milker** is a powerful cross-platform CLI tool to bulk download photos from Boosty.to creators.
|
|
21
|
+
|
|
22
|
+
🚀 **Features:**
|
|
23
|
+
* 📥 Download all photos from all posts of a creator.
|
|
24
|
+
* 🔓 Support for premium/subscriber-only content (via auth token).
|
|
25
|
+
* ⚡ Async downloads (fast and efficient).
|
|
26
|
+
* 🖥️ Works on **Windows, macOS, and Linux**.
|
|
27
|
+
* 💾 Smart download (skips already existing files).
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## 📦 Installation
|
|
32
|
+
|
|
33
|
+
### 🍎 macOS (Homebrew)
|
|
34
|
+
The easiest way for Mac users:
|
|
35
|
+
```bash
|
|
36
|
+
brew tap F3T1W/tap
|
|
37
|
+
brew install boosty-milker
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 🐧 Linux (Debian / Ubuntu / APT)
|
|
41
|
+
Add the repository and install:
|
|
42
|
+
```bash
|
|
43
|
+
echo "deb [trusted=yes] https://F3T1W.github.io/apt-repo stable main" | sudo tee /etc/apt/sources.list.d/f3t1w.list
|
|
44
|
+
sudo apt-get update
|
|
45
|
+
sudo apt-get install boosty-milker
|
|
46
|
+
```
|
|
47
|
+
*Alternatively, download the `.deb` file manually from [Releases](https://github.com/F3T1W/BoostyMilker/releases).*
|
|
48
|
+
|
|
49
|
+
### 🪟 Windows (Chocolatey)
|
|
50
|
+
Install via PowerShell:
|
|
51
|
+
```powershell
|
|
52
|
+
choco install boosty-milker
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### 🐍 Python (PIP)
|
|
56
|
+
Universal method for any OS (requires Python 3.10+):
|
|
57
|
+
```bash
|
|
58
|
+
pip install boosty-milker
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 📁 Manual Binaries
|
|
62
|
+
If you don't want to install anything, just download the executable for your OS from **[Releases](https://github.com/F3T1W/BoostyMilker/releases)**, place it in a convenient folder, and run it via terminal.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 🚀 Usage
|
|
67
|
+
|
|
68
|
+
### 1. Download Free Posts
|
|
69
|
+
```bash
|
|
70
|
+
boosty-milker --username "artist_name" --directory "./downloads"
|
|
71
|
+
```
|
|
72
|
+
* `artist_name` — creator's username from the URL (e.g., for `boosty.to/cool_art` the username is `cool_art`).
|
|
73
|
+
* `directory` — folder to save photos.
|
|
74
|
+
|
|
75
|
+
### 2. Download Premium Content (Subscribers)
|
|
76
|
+
If you are subscribed to a creator, you need to provide your auth token to download private posts.
|
|
77
|
+
|
|
78
|
+
1. Open [Boosty.to](https://boosty.to) in your browser.
|
|
79
|
+
2. Press `F12` -> Go to **Application** (or Storage) tab.
|
|
80
|
+
3. In the left menu, select **Cookies** -> `https://boosty.to`.
|
|
81
|
+
4. Find the cookie named `auth_token` or `accessToken` and copy its value.
|
|
82
|
+
|
|
83
|
+
Run:
|
|
84
|
+
```bash
|
|
85
|
+
boosty-milker --username "artist_name" --directory "./downloads" --auth_token "YOUR_TOKEN"
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### All Arguments
|
|
89
|
+
```text
|
|
90
|
+
options:
|
|
91
|
+
-h, --help show this help message
|
|
92
|
+
--username USERNAME Boosty creator username (from URL)
|
|
93
|
+
--directory DIRECTORY Directory to save photos
|
|
94
|
+
--auth_token TOKEN Auth token (Bearer/accessToken) for private content
|
|
95
|
+
--max_concurrency N Number of concurrent downloads (default: 10)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## ⚠️ Disclaimer
|
|
101
|
+
This tool is for personal use only. Please only download content you have legal access to. The author is not responsible for any misuse of this software or violations of Boosty.to terms of service.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
Made with ❤️ by [F3T1W](https://github.com/F3T1W)
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Boosty Milker 🥛
|
|
2
|
+
|
|
3
|
+
[](https://github.com/F3T1W/BoostyMilker/releases)
|
|
4
|
+
[](https://pypi.org/project/boosty-milker/)
|
|
5
|
+
[](https://community.chocolatey.org/packages/boosty-milker)
|
|
6
|
+
[](https://github.com/F3T1W/homebrew-tap)
|
|
7
|
+
[](https://github.com/F3T1W/apt-repo)
|
|
8
|
+
|
|
9
|
+
**Boosty Milker** is a powerful cross-platform CLI tool to bulk download photos from Boosty.to creators.
|
|
10
|
+
|
|
11
|
+
🚀 **Features:**
|
|
12
|
+
* 📥 Download all photos from all posts of a creator.
|
|
13
|
+
* 🔓 Support for premium/subscriber-only content (via auth token).
|
|
14
|
+
* ⚡ Async downloads (fast and efficient).
|
|
15
|
+
* 🖥️ Works on **Windows, macOS, and Linux**.
|
|
16
|
+
* 💾 Smart download (skips already existing files).
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 📦 Installation
|
|
21
|
+
|
|
22
|
+
### 🍎 macOS (Homebrew)
|
|
23
|
+
The easiest way for Mac users:
|
|
24
|
+
```bash
|
|
25
|
+
brew tap F3T1W/tap
|
|
26
|
+
brew install boosty-milker
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### 🐧 Linux (Debian / Ubuntu / APT)
|
|
30
|
+
Add the repository and install:
|
|
31
|
+
```bash
|
|
32
|
+
echo "deb [trusted=yes] https://F3T1W.github.io/apt-repo stable main" | sudo tee /etc/apt/sources.list.d/f3t1w.list
|
|
33
|
+
sudo apt-get update
|
|
34
|
+
sudo apt-get install boosty-milker
|
|
35
|
+
```
|
|
36
|
+
*Alternatively, download the `.deb` file manually from [Releases](https://github.com/F3T1W/BoostyMilker/releases).*
|
|
37
|
+
|
|
38
|
+
### 🪟 Windows (Chocolatey)
|
|
39
|
+
Install via PowerShell:
|
|
40
|
+
```powershell
|
|
41
|
+
choco install boosty-milker
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 🐍 Python (PIP)
|
|
45
|
+
Universal method for any OS (requires Python 3.10+):
|
|
46
|
+
```bash
|
|
47
|
+
pip install boosty-milker
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 📁 Manual Binaries
|
|
51
|
+
If you don't want to install anything, just download the executable for your OS from **[Releases](https://github.com/F3T1W/BoostyMilker/releases)**, place it in a convenient folder, and run it via terminal.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## 🚀 Usage
|
|
56
|
+
|
|
57
|
+
### 1. Download Free Posts
|
|
58
|
+
```bash
|
|
59
|
+
boosty-milker --username "artist_name" --directory "./downloads"
|
|
60
|
+
```
|
|
61
|
+
* `artist_name` — creator's username from the URL (e.g., for `boosty.to/cool_art` the username is `cool_art`).
|
|
62
|
+
* `directory` — folder to save photos.
|
|
63
|
+
|
|
64
|
+
### 2. Download Premium Content (Subscribers)
|
|
65
|
+
If you are subscribed to a creator, you need to provide your auth token to download private posts.
|
|
66
|
+
|
|
67
|
+
1. Open [Boosty.to](https://boosty.to) in your browser.
|
|
68
|
+
2. Press `F12` -> Go to **Application** (or Storage) tab.
|
|
69
|
+
3. In the left menu, select **Cookies** -> `https://boosty.to`.
|
|
70
|
+
4. Find the cookie named `auth_token` or `accessToken` and copy its value.
|
|
71
|
+
|
|
72
|
+
Run:
|
|
73
|
+
```bash
|
|
74
|
+
boosty-milker --username "artist_name" --directory "./downloads" --auth_token "YOUR_TOKEN"
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### All Arguments
|
|
78
|
+
```text
|
|
79
|
+
options:
|
|
80
|
+
-h, --help show this help message
|
|
81
|
+
--username USERNAME Boosty creator username (from URL)
|
|
82
|
+
--directory DIRECTORY Directory to save photos
|
|
83
|
+
--auth_token TOKEN Auth token (Bearer/accessToken) for private content
|
|
84
|
+
--max_concurrency N Number of concurrent downloads (default: 10)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## ⚠️ Disclaimer
|
|
90
|
+
This tool is for personal use only. Please only download content you have legal access to. The author is not responsible for any misuse of this software or violations of Boosty.to terms of service.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
Made with ❤️ by [F3T1W](https://github.com/F3T1W)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.0.0"
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import asyncio
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
import logging
|
|
6
|
+
import json
|
|
7
|
+
import re
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import List, Optional, Dict, Any
|
|
10
|
+
from datetime import datetime
|
|
11
|
+
|
|
12
|
+
import aiohttp
|
|
13
|
+
from tqdm.asyncio import tqdm
|
|
14
|
+
from colorama import init, Fore, Style
|
|
15
|
+
|
|
16
|
+
# Initialize colorama
|
|
17
|
+
init(autoreset=True)
|
|
18
|
+
|
|
19
|
+
# Logging setup
|
|
20
|
+
logging.basicConfig(
|
|
21
|
+
level=logging.INFO,
|
|
22
|
+
format='%(asctime)s - %(levelname)s - %(message)s',
|
|
23
|
+
handlers=[logging.StreamHandler(sys.stdout)]
|
|
24
|
+
)
|
|
25
|
+
logger = logging.getLogger("boosty-milker")
|
|
26
|
+
|
|
27
|
+
class BoostyClient:
|
|
28
|
+
API_URL = "https://api.boosty.to/v1/blog/{}/post/"
|
|
29
|
+
|
|
30
|
+
def __init__(self, session: aiohttp.ClientSession, auth_token: Optional[str] = None):
|
|
31
|
+
self.session = session
|
|
32
|
+
self.auth_token = auth_token
|
|
33
|
+
self.headers = {
|
|
34
|
+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
|
|
35
|
+
"Accept": "application/json, text/plain, */*",
|
|
36
|
+
"Origin": "https://boosty.to",
|
|
37
|
+
"Referer": "https://boosty.to/"
|
|
38
|
+
}
|
|
39
|
+
if self.auth_token:
|
|
40
|
+
self.headers["Authorization"] = f"Bearer {self.auth_token}"
|
|
41
|
+
|
|
42
|
+
async def get_posts(self, blog_name: str, limit: int = 100, offset: str = "") -> Dict[str, Any]:
|
|
43
|
+
url = self.API_URL.format(blog_name)
|
|
44
|
+
params = {
|
|
45
|
+
"limit": limit,
|
|
46
|
+
"comments_limit": 0,
|
|
47
|
+
"reply_limit": 0,
|
|
48
|
+
}
|
|
49
|
+
if offset:
|
|
50
|
+
params["offset"] = offset
|
|
51
|
+
|
|
52
|
+
async with self.session.get(url, params=params, headers=self.headers) as resp:
|
|
53
|
+
if resp.status == 401:
|
|
54
|
+
logger.error(f"{Fore.RED}Unauthorized. Please provide a valid auth token for private content.")
|
|
55
|
+
return {}
|
|
56
|
+
if resp.status == 403:
|
|
57
|
+
logger.error(f"{Fore.RED}Access denied. Check your token or subscription.")
|
|
58
|
+
return {}
|
|
59
|
+
if resp.status != 200:
|
|
60
|
+
logger.error(f"{Fore.RED}Error fetching posts: {resp.status}")
|
|
61
|
+
return {}
|
|
62
|
+
return await resp.json()
|
|
63
|
+
|
|
64
|
+
class Downloader:
|
|
65
|
+
def __init__(self, download_dir: Path, max_concurrency: int = 5):
|
|
66
|
+
self.download_dir = download_dir
|
|
67
|
+
self.semaphore = asyncio.Semaphore(max_concurrency)
|
|
68
|
+
self.download_dir.mkdir(parents=True, exist_ok=True)
|
|
69
|
+
|
|
70
|
+
async def download_file(self, session: aiohttp.ClientSession, url: str, filename: str) -> bool:
|
|
71
|
+
filepath = self.download_dir / filename
|
|
72
|
+
|
|
73
|
+
# Simple sanitization
|
|
74
|
+
filepath = Path(str(filepath).split("?")[0]) # Remove query params from filename if present
|
|
75
|
+
|
|
76
|
+
if filepath.exists():
|
|
77
|
+
return True # Skip existing
|
|
78
|
+
|
|
79
|
+
async with self.semaphore:
|
|
80
|
+
try:
|
|
81
|
+
async with session.get(url) as resp:
|
|
82
|
+
if resp.status == 200:
|
|
83
|
+
content = await resp.read()
|
|
84
|
+
with open(filepath, "wb") as f:
|
|
85
|
+
f.write(content)
|
|
86
|
+
return True
|
|
87
|
+
else:
|
|
88
|
+
logger.warning(f"Failed to download {url}: {resp.status}")
|
|
89
|
+
return False
|
|
90
|
+
except Exception as e:
|
|
91
|
+
logger.error(f"Error downloading {url}: {e}")
|
|
92
|
+
return False
|
|
93
|
+
|
|
94
|
+
async def process_post(post: Dict[str, Any], downloader: Downloader, session: aiohttp.ClientSession, tasks: List[Any]):
|
|
95
|
+
post_id = post.get("id")
|
|
96
|
+
title = post.get("title", "")
|
|
97
|
+
published = post.get("publishTime", 0)
|
|
98
|
+
date_str = datetime.fromtimestamp(published).strftime('%Y-%m-%d')
|
|
99
|
+
|
|
100
|
+
# Process data blocks
|
|
101
|
+
data_blocks = post.get("data", [])
|
|
102
|
+
if not data_blocks:
|
|
103
|
+
return
|
|
104
|
+
|
|
105
|
+
img_count = 0
|
|
106
|
+
for block in data_blocks:
|
|
107
|
+
block_type = block.get("type")
|
|
108
|
+
url = None
|
|
109
|
+
|
|
110
|
+
if block_type == "image":
|
|
111
|
+
url = block.get("url")
|
|
112
|
+
# Sometimes URL is inside 'content'
|
|
113
|
+
if not url and "content" in block:
|
|
114
|
+
# content might be a string (unlikely for image) or object
|
|
115
|
+
pass
|
|
116
|
+
|
|
117
|
+
# High quality URL is usually main URL
|
|
118
|
+
|
|
119
|
+
# Handle teaser blocks for locked posts if visible
|
|
120
|
+
if block_type == "teaser_image":
|
|
121
|
+
pass # Usually blurred, skip
|
|
122
|
+
|
|
123
|
+
if url:
|
|
124
|
+
img_count += 1
|
|
125
|
+
filename = f"{date_str}_post{post_id}_{img_count}.jpg"
|
|
126
|
+
tasks.append(downloader.download_file(session, url, filename))
|
|
127
|
+
|
|
128
|
+
# Boosty structure varies; sometimes 'teaser' contains images if locked but we have access?
|
|
129
|
+
# Usually 'data' contains the content we can see.
|
|
130
|
+
|
|
131
|
+
async def main():
|
|
132
|
+
parser = argparse.ArgumentParser(description="Boosty Milker - Photo Downloader")
|
|
133
|
+
parser.add_argument("--username", required=True, help="Boosty creator username")
|
|
134
|
+
parser.add_argument("--directory", required=True, help="Directory to save photos")
|
|
135
|
+
parser.add_argument("--auth_token", help="Bearer token for private content", default=None)
|
|
136
|
+
parser.add_argument("--max_concurrency", type=int, default=10, help="Max concurrent downloads")
|
|
137
|
+
|
|
138
|
+
args = parser.parse_args()
|
|
139
|
+
|
|
140
|
+
auth_token = args.auth_token
|
|
141
|
+
if not auth_token:
|
|
142
|
+
# Check env var
|
|
143
|
+
auth_token = os.environ.get("BOOSTY_TOKEN")
|
|
144
|
+
|
|
145
|
+
async with aiohttp.ClientSession() as session:
|
|
146
|
+
client = BoostyClient(session, auth_token)
|
|
147
|
+
downloader = Downloader(Path(args.directory), args.max_concurrency)
|
|
148
|
+
|
|
149
|
+
logger.info(f"{Fore.CYAN}Starting download for user: {args.username}")
|
|
150
|
+
if auth_token:
|
|
151
|
+
logger.info(f"{Fore.GREEN}Authenticated with token.")
|
|
152
|
+
|
|
153
|
+
offset = ""
|
|
154
|
+
tasks = []
|
|
155
|
+
total_posts = 0
|
|
156
|
+
|
|
157
|
+
pbar_posts = tqdm(desc="Fetching posts", unit="page")
|
|
158
|
+
|
|
159
|
+
while True:
|
|
160
|
+
data = await client.get_posts(args.username, offset=offset)
|
|
161
|
+
if not data or "data" not in data:
|
|
162
|
+
break
|
|
163
|
+
|
|
164
|
+
posts = data["data"]
|
|
165
|
+
if not posts:
|
|
166
|
+
break
|
|
167
|
+
|
|
168
|
+
for post in posts:
|
|
169
|
+
process_post_sync(post, tasks, downloader, session)
|
|
170
|
+
|
|
171
|
+
total_posts += len(posts)
|
|
172
|
+
pbar_posts.update(1)
|
|
173
|
+
|
|
174
|
+
extra = data.get("extra", {})
|
|
175
|
+
offset = extra.get("offset")
|
|
176
|
+
if not offset:
|
|
177
|
+
break
|
|
178
|
+
|
|
179
|
+
pbar_posts.close()
|
|
180
|
+
logger.info(f"Found {len(tasks)} images in {total_posts} posts.")
|
|
181
|
+
|
|
182
|
+
if tasks:
|
|
183
|
+
results = await tqdm.gather(*tasks, desc="Downloading images", unit="img")
|
|
184
|
+
success_count = sum(results)
|
|
185
|
+
logger.info(f"{Fore.GREEN}Downloaded {success_count}/{len(tasks)} images.")
|
|
186
|
+
else:
|
|
187
|
+
logger.info("No images found.")
|
|
188
|
+
|
|
189
|
+
def process_post_sync(post, tasks, downloader, session):
|
|
190
|
+
"""Synchronous helper to extract URLs and add tasks"""
|
|
191
|
+
post_id = post.get("id")
|
|
192
|
+
published = post.get("publishTime", 0)
|
|
193
|
+
date_str = datetime.fromtimestamp(published).strftime('%Y-%m-%d')
|
|
194
|
+
|
|
195
|
+
data_blocks = post.get("data", [])
|
|
196
|
+
if not data_blocks:
|
|
197
|
+
return
|
|
198
|
+
|
|
199
|
+
img_count = 0
|
|
200
|
+
for block in data_blocks:
|
|
201
|
+
if block.get("type") == "image":
|
|
202
|
+
url = block.get("url")
|
|
203
|
+
# Try to get max resolution
|
|
204
|
+
# The 'url' field is usually the full size or decent size.
|
|
205
|
+
# Sometimes there are 'resolutions' or 'urls' map?
|
|
206
|
+
# Boosty API 'image' block usually has 'url' at top level.
|
|
207
|
+
|
|
208
|
+
if url:
|
|
209
|
+
img_count += 1
|
|
210
|
+
# Clean URL
|
|
211
|
+
if "?" in url:
|
|
212
|
+
clean_url = url # Keep params for download if signed, but filename needs clean ext
|
|
213
|
+
|
|
214
|
+
# Deduce extension
|
|
215
|
+
ext = ".jpg"
|
|
216
|
+
if ".png" in url.lower(): ext = ".png"
|
|
217
|
+
elif ".webp" in url.lower(): ext = ".webp"
|
|
218
|
+
|
|
219
|
+
filename = f"{date_str}_{post_id}_img{img_count}{ext}"
|
|
220
|
+
tasks.append(downloader.download_file(session, url, filename))
|
|
221
|
+
|
|
222
|
+
if __name__ == "__main__":
|
|
223
|
+
if sys.platform == 'win32':
|
|
224
|
+
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
|
225
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: boosty-milker
|
|
3
|
+
Version: 1.0.1
|
|
4
|
+
Summary: CLI tool to download photos from Boosty.to
|
|
5
|
+
Author-email: F3T1W <f3t1w@icloud.com>
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: aiohttp>=3.8.0
|
|
9
|
+
Requires-Dist: tqdm>=4.65.0
|
|
10
|
+
Requires-Dist: colorama>=0.4.6
|
|
11
|
+
|
|
12
|
+
# Boosty Milker 🥛
|
|
13
|
+
|
|
14
|
+
[](https://github.com/F3T1W/BoostyMilker/releases)
|
|
15
|
+
[](https://pypi.org/project/boosty-milker/)
|
|
16
|
+
[](https://community.chocolatey.org/packages/boosty-milker)
|
|
17
|
+
[](https://github.com/F3T1W/homebrew-tap)
|
|
18
|
+
[](https://github.com/F3T1W/apt-repo)
|
|
19
|
+
|
|
20
|
+
**Boosty Milker** is a powerful cross-platform CLI tool to bulk download photos from Boosty.to creators.
|
|
21
|
+
|
|
22
|
+
🚀 **Features:**
|
|
23
|
+
* 📥 Download all photos from all posts of a creator.
|
|
24
|
+
* 🔓 Support for premium/subscriber-only content (via auth token).
|
|
25
|
+
* ⚡ Async downloads (fast and efficient).
|
|
26
|
+
* 🖥️ Works on **Windows, macOS, and Linux**.
|
|
27
|
+
* 💾 Smart download (skips already existing files).
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## 📦 Installation
|
|
32
|
+
|
|
33
|
+
### 🍎 macOS (Homebrew)
|
|
34
|
+
The easiest way for Mac users:
|
|
35
|
+
```bash
|
|
36
|
+
brew tap F3T1W/tap
|
|
37
|
+
brew install boosty-milker
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 🐧 Linux (Debian / Ubuntu / APT)
|
|
41
|
+
Add the repository and install:
|
|
42
|
+
```bash
|
|
43
|
+
echo "deb [trusted=yes] https://F3T1W.github.io/apt-repo stable main" | sudo tee /etc/apt/sources.list.d/f3t1w.list
|
|
44
|
+
sudo apt-get update
|
|
45
|
+
sudo apt-get install boosty-milker
|
|
46
|
+
```
|
|
47
|
+
*Alternatively, download the `.deb` file manually from [Releases](https://github.com/F3T1W/BoostyMilker/releases).*
|
|
48
|
+
|
|
49
|
+
### 🪟 Windows (Chocolatey)
|
|
50
|
+
Install via PowerShell:
|
|
51
|
+
```powershell
|
|
52
|
+
choco install boosty-milker
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### 🐍 Python (PIP)
|
|
56
|
+
Universal method for any OS (requires Python 3.10+):
|
|
57
|
+
```bash
|
|
58
|
+
pip install boosty-milker
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 📁 Manual Binaries
|
|
62
|
+
If you don't want to install anything, just download the executable for your OS from **[Releases](https://github.com/F3T1W/BoostyMilker/releases)**, place it in a convenient folder, and run it via terminal.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 🚀 Usage
|
|
67
|
+
|
|
68
|
+
### 1. Download Free Posts
|
|
69
|
+
```bash
|
|
70
|
+
boosty-milker --username "artist_name" --directory "./downloads"
|
|
71
|
+
```
|
|
72
|
+
* `artist_name` — creator's username from the URL (e.g., for `boosty.to/cool_art` the username is `cool_art`).
|
|
73
|
+
* `directory` — folder to save photos.
|
|
74
|
+
|
|
75
|
+
### 2. Download Premium Content (Subscribers)
|
|
76
|
+
If you are subscribed to a creator, you need to provide your auth token to download private posts.
|
|
77
|
+
|
|
78
|
+
1. Open [Boosty.to](https://boosty.to) in your browser.
|
|
79
|
+
2. Press `F12` -> Go to **Application** (or Storage) tab.
|
|
80
|
+
3. In the left menu, select **Cookies** -> `https://boosty.to`.
|
|
81
|
+
4. Find the cookie named `auth_token` or `accessToken` and copy its value.
|
|
82
|
+
|
|
83
|
+
Run:
|
|
84
|
+
```bash
|
|
85
|
+
boosty-milker --username "artist_name" --directory "./downloads" --auth_token "YOUR_TOKEN"
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### All Arguments
|
|
89
|
+
```text
|
|
90
|
+
options:
|
|
91
|
+
-h, --help show this help message
|
|
92
|
+
--username USERNAME Boosty creator username (from URL)
|
|
93
|
+
--directory DIRECTORY Directory to save photos
|
|
94
|
+
--auth_token TOKEN Auth token (Bearer/accessToken) for private content
|
|
95
|
+
--max_concurrency N Number of concurrent downloads (default: 10)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## ⚠️ Disclaimer
|
|
101
|
+
This tool is for personal use only. Please only download content you have legal access to. The author is not responsible for any misuse of this software or violations of Boosty.to terms of service.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
Made with ❤️ by [F3T1W](https://github.com/F3T1W)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
boosty_milker/__init__.py
|
|
4
|
+
boosty_milker/main.py
|
|
5
|
+
boosty_milker.egg-info/PKG-INFO
|
|
6
|
+
boosty_milker.egg-info/SOURCES.txt
|
|
7
|
+
boosty_milker.egg-info/dependency_links.txt
|
|
8
|
+
boosty_milker.egg-info/entry_points.txt
|
|
9
|
+
boosty_milker.egg-info/requires.txt
|
|
10
|
+
boosty_milker.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
boosty_milker
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "boosty-milker"
|
|
7
|
+
version = "1.0.1"
|
|
8
|
+
description = "CLI tool to download photos from Boosty.to"
|
|
9
|
+
authors = [{ name = "F3T1W", email = "f3t1w@icloud.com" }]
|
|
10
|
+
readme = "README.md"
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
dependencies = [
|
|
13
|
+
"aiohttp>=3.8.0",
|
|
14
|
+
"tqdm>=4.65.0",
|
|
15
|
+
"colorama>=0.4.6"
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
[project.scripts]
|
|
19
|
+
boosty-milker = "boosty_milker.main:main"
|
|
20
|
+
|
|
21
|
+
[tool.setuptools]
|
|
22
|
+
packages = ["boosty_milker"]
|