jugs 1.0.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.
- jugs-1.0.0/.github/workflows/publish.yml +40 -0
- jugs-1.0.0/PKG-INFO +10 -0
- jugs-1.0.0/README.md +178 -0
- jugs-1.0.0/examples/auth.py +17 -0
- jugs-1.0.0/examples/basic.py +13 -0
- jugs-1.0.0/examples/multi_account_demo.py +241 -0
- jugs-1.0.0/examples/proxy.py +18 -0
- jugs-1.0.0/examples/requirements-demo.txt +2 -0
- jugs-1.0.0/jugs/__init__.py +43 -0
- jugs-1.0.0/jugs/auth.py +172 -0
- jugs-1.0.0/jugs/client.py +158 -0
- jugs-1.0.0/jugs/constants.py +59 -0
- jugs-1.0.0/jugs/endpoints/__init__.py +7 -0
- jugs-1.0.0/jugs/endpoints/actions.py +89 -0
- jugs-1.0.0/jugs/endpoints/discord.py +63 -0
- jugs-1.0.0/jugs/endpoints/sys.py +215 -0
- jugs-1.0.0/jugs/exceptions.py +29 -0
- jugs-1.0.0/jugs/http.py +179 -0
- jugs-1.0.0/jugs/models.py +74 -0
- jugs-1.0.0/pyproject.toml +19 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
publish:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
environment:
|
|
15
|
+
name: pypi
|
|
16
|
+
url: https://pypi.org/p/jugs
|
|
17
|
+
|
|
18
|
+
steps:
|
|
19
|
+
- name: Checkout
|
|
20
|
+
uses: actions/checkout@v4
|
|
21
|
+
|
|
22
|
+
- name: Set up Python
|
|
23
|
+
uses: actions/setup-python@v5
|
|
24
|
+
with:
|
|
25
|
+
python-version: "3.12"
|
|
26
|
+
|
|
27
|
+
- name: Install build tools
|
|
28
|
+
run: |
|
|
29
|
+
python -m pip install --upgrade pip
|
|
30
|
+
pip install build twine
|
|
31
|
+
|
|
32
|
+
- name: Build package
|
|
33
|
+
run: python -m build
|
|
34
|
+
|
|
35
|
+
- name: Publish to PyPI
|
|
36
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
37
|
+
with:
|
|
38
|
+
user: __token__
|
|
39
|
+
password: ${{ secrets.pypi }}
|
|
40
|
+
verbose: true
|
jugs-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: jugs
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: High-performance Python client for jugs.lol
|
|
5
|
+
Requires-Python: >=3.10
|
|
6
|
+
Requires-Dist: httpx[http2]>=0.27.0
|
|
7
|
+
Requires-Dist: orjson>=3.10.0
|
|
8
|
+
Provides-Extra: dev
|
|
9
|
+
Requires-Dist: pytest; extra == 'dev'
|
|
10
|
+
Requires-Dist: pytest-asyncio; extra == 'dev'
|
jugs-1.0.0/README.md
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# jugs
|
|
2
|
+
|
|
3
|
+
High-performance Python client for [jugs.lol](https://jugs.lol).
|
|
4
|
+
|
|
5
|
+
Blazing fast. Minimal overhead. Fully typed. Proxy rotation. Session/auth support.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install -e .
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Requires Python 3.10+.
|
|
14
|
+
|
|
15
|
+
Dependencies: `httpx[http2]`, `orjson`.
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
from jugs import JugsClient
|
|
21
|
+
|
|
22
|
+
with JugsClient("c") as client:
|
|
23
|
+
print(client.view())
|
|
24
|
+
print(client.status())
|
|
25
|
+
print(client.comments())
|
|
26
|
+
print(client.presence("1274550388594311188"))
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Features
|
|
30
|
+
|
|
31
|
+
- All public `/api/sys/*` endpoints
|
|
32
|
+
- Discord presence
|
|
33
|
+
- Link click tracking
|
|
34
|
+
- Next.js server actions (tips, drops, crates)
|
|
35
|
+
- Email login / signup via Supabase Auth
|
|
36
|
+
- Discord OAuth URL helper
|
|
37
|
+
- Session load / refresh / logout
|
|
38
|
+
- Proxy rotation (round-robin + random)
|
|
39
|
+
- HTTP/2 + orjson for max speed
|
|
40
|
+
- Zero comments / docstrings in source (clean, dense code)
|
|
41
|
+
- Strict type hints + `slots=True` dataclasses
|
|
42
|
+
- Context manager support
|
|
43
|
+
|
|
44
|
+
## Proxy Rotation
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
proxies = [
|
|
48
|
+
"http://user:pass@ip1:port",
|
|
49
|
+
"http://user:pass@ip2:port",
|
|
50
|
+
"socks5://ip3:port",
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
client = JugsClient("c", proxies=proxies)
|
|
54
|
+
|
|
55
|
+
# Auto-rotate on view
|
|
56
|
+
client.view(rotate=True)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Authentication
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
client = JugsClient("c")
|
|
63
|
+
|
|
64
|
+
# Email
|
|
65
|
+
client.login("you@example.com", "password")
|
|
66
|
+
client.signup("you@example.com", "password")
|
|
67
|
+
|
|
68
|
+
# Load existing tokens
|
|
69
|
+
client.load_session(access_token="...", refresh_token="...")
|
|
70
|
+
|
|
71
|
+
# Refresh
|
|
72
|
+
client.refresh_session()
|
|
73
|
+
|
|
74
|
+
# Discord OAuth (open in browser)
|
|
75
|
+
print(client.discord_oauth_url())
|
|
76
|
+
|
|
77
|
+
# Logout
|
|
78
|
+
client.logout()
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Full API Surface
|
|
82
|
+
|
|
83
|
+
### Profile / Social
|
|
84
|
+
|
|
85
|
+
| Method | Description |
|
|
86
|
+
|--------|-------------|
|
|
87
|
+
| `view(username=None, rotate=False)` | Increment view counter |
|
|
88
|
+
| `status(username=None)` | Bookmarks + likes counts |
|
|
89
|
+
| `likes(username=None)` | Alias of status |
|
|
90
|
+
| `click(url, username=None)` | Track link click |
|
|
91
|
+
| `comments(username=None)` | Fetch comments |
|
|
92
|
+
| `post_comment(content, username=None)` | Post comment (auth) |
|
|
93
|
+
|
|
94
|
+
### Discord
|
|
95
|
+
|
|
96
|
+
| Method | Description |
|
|
97
|
+
|--------|-------------|
|
|
98
|
+
| `presence(discord_id)` | Live status, activities, roles |
|
|
99
|
+
|
|
100
|
+
### Server Actions
|
|
101
|
+
|
|
102
|
+
| Method | Description |
|
|
103
|
+
|--------|-------------|
|
|
104
|
+
| `tip(payload=None)` | Send credits tip (auth) |
|
|
105
|
+
| `claim_drop(drop_id)` | Claim Discord credit drop |
|
|
106
|
+
| `claim_crate(crate_id)` | Claim crate drop |
|
|
107
|
+
| `get_unseen_drops()` | Unseen credit drops |
|
|
108
|
+
| `get_unseen_crates()` | Unseen crate drops |
|
|
109
|
+
| `mark_drops_seen()` | Mark drops seen |
|
|
110
|
+
| `mark_crates_seen()` | Mark crates seen |
|
|
111
|
+
|
|
112
|
+
### Feedback
|
|
113
|
+
|
|
114
|
+
| Method | Description |
|
|
115
|
+
|--------|-------------|
|
|
116
|
+
| `bug_check()` | Check bug report eligibility |
|
|
117
|
+
| `bug_report(...)` | Submit bug report (auth) |
|
|
118
|
+
| `suggest_check()` | Check suggest eligibility |
|
|
119
|
+
| `suggest(text, context="")` | Submit suggestion (auth) |
|
|
120
|
+
|
|
121
|
+
### Auth
|
|
122
|
+
|
|
123
|
+
| Method | Description |
|
|
124
|
+
|--------|-------------|
|
|
125
|
+
| `login(email, password)` | Email/password login |
|
|
126
|
+
| `signup(email, password)` | Email signup |
|
|
127
|
+
| `load_session(access, refresh=None)` | Inject tokens |
|
|
128
|
+
| `refresh_session()` | Refresh tokens |
|
|
129
|
+
| `logout()` | Clear session |
|
|
130
|
+
| `discord_oauth_url(redirect=None)` | Get Discord OAuth URL |
|
|
131
|
+
|
|
132
|
+
## Models
|
|
133
|
+
|
|
134
|
+
All responses are typed dataclasses (`slots=True`, frozen where possible):
|
|
135
|
+
|
|
136
|
+
- `ViewResult`
|
|
137
|
+
- `StatusResult`
|
|
138
|
+
- `CommentsResult` / `Comment`
|
|
139
|
+
- `PresenceResult` / `DiscordUser` / `DiscordMember`
|
|
140
|
+
- `ClickResult`
|
|
141
|
+
- `ActionResult`
|
|
142
|
+
|
|
143
|
+
## Architecture
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
jugs/
|
|
147
|
+
├── __init__.py
|
|
148
|
+
├── client.py # JugsClient facade
|
|
149
|
+
├── http.py # HTTPSession + ProxyRotator
|
|
150
|
+
├── auth.py # AuthManager (Supabase)
|
|
151
|
+
├── constants.py
|
|
152
|
+
├── exceptions.py
|
|
153
|
+
├── models.py
|
|
154
|
+
└── endpoints/
|
|
155
|
+
├── sys.py # /api/sys/*
|
|
156
|
+
├── discord.py
|
|
157
|
+
└── actions.py # Next.js server actions
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Performance Notes
|
|
161
|
+
|
|
162
|
+
- `orjson` for all serialization (significantly faster than stdlib json)
|
|
163
|
+
- `httpx` with HTTP/2
|
|
164
|
+
- `__slots__` everywhere to cut memory + attribute lookup cost
|
|
165
|
+
- Frozen dataclasses for response objects
|
|
166
|
+
- No unnecessary abstractions
|
|
167
|
+
- Connection reuse via persistent session
|
|
168
|
+
- Optional per-request proxy rotation
|
|
169
|
+
|
|
170
|
+
## Reserved Usernames
|
|
171
|
+
|
|
172
|
+
These cannot be used as profile handles:
|
|
173
|
+
|
|
174
|
+
`login`, `signup`, `dashboard`, `api`, `admin`, `owner`, `auth`, `about`, `terms`, `privacy`, `leaderboard`, `directory`, `discord`, `shop`, `addons`, `claim`, `premium`, `crates`, `reset-password`, `account-restricted`, `_next`, `static`
|
|
175
|
+
|
|
176
|
+
## License
|
|
177
|
+
|
|
178
|
+
Private. All rights reserved.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from jugs import JugsClient
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def main() -> None:
|
|
5
|
+
client = JugsClient("c")
|
|
6
|
+
|
|
7
|
+
print(client.discord_oauth_url())
|
|
8
|
+
|
|
9
|
+
# client.login("email@example.com", "password")
|
|
10
|
+
# client.signup("email@example.com", "password")
|
|
11
|
+
# client.load_session("access_token_here", "refresh_token_here")
|
|
12
|
+
|
|
13
|
+
client.close()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
if __name__ == "__main__":
|
|
17
|
+
main()
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from jugs import JugsClient
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def main() -> None:
|
|
5
|
+
with JugsClient("c") as client:
|
|
6
|
+
print(client.view())
|
|
7
|
+
print(client.status())
|
|
8
|
+
print(client.comments())
|
|
9
|
+
print(client.presence("1274550388594311188"))
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
if __name__ == "__main__":
|
|
13
|
+
main()
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import random
|
|
5
|
+
import string
|
|
6
|
+
import sys
|
|
7
|
+
import time
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from rich import box
|
|
12
|
+
from rich.console import Console
|
|
13
|
+
from rich.panel import Panel
|
|
14
|
+
from rich.table import Table
|
|
15
|
+
from rich.text import Text
|
|
16
|
+
from rich.align import Align
|
|
17
|
+
from rich.rule import Rule
|
|
18
|
+
from rich.progress import Progress, SpinnerColumn, TextColumn, BarColumn
|
|
19
|
+
|
|
20
|
+
from jugs import JugsClient
|
|
21
|
+
from jugs.exceptions import AuthError, JugsError
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
console = Console()
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass(slots=True)
|
|
28
|
+
class AccountResult:
|
|
29
|
+
email: str
|
|
30
|
+
password: str
|
|
31
|
+
ok: bool
|
|
32
|
+
user_id: str | None = None
|
|
33
|
+
username_hint: str | None = None
|
|
34
|
+
access_token: str | None = None
|
|
35
|
+
error: str | None = None
|
|
36
|
+
unseen_drops: Any = None
|
|
37
|
+
unseen_crates: Any = None
|
|
38
|
+
session_user: dict[str, Any] | None = None
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def random_string(length: int = 10) -> str:
|
|
42
|
+
alphabet = string.ascii_lowercase + string.digits
|
|
43
|
+
return "".join(random.choices(alphabet, k=length))
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def generate_account() -> tuple[str, str]:
|
|
47
|
+
user = random_string(8)
|
|
48
|
+
domain = random.choice(["gmail.com", "outlook.com", "proton.me", "yahoo.com"])
|
|
49
|
+
email = f"{user}.{random_string(4)}@{domain}"
|
|
50
|
+
password = random_string(12) + random.choice("!@#$%") + str(random.randint(10, 99))
|
|
51
|
+
return email, password
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def create_account(client: JugsClient, email: str, password: str) -> AccountResult:
|
|
55
|
+
result = AccountResult(email=email, password=password, ok=False)
|
|
56
|
+
|
|
57
|
+
try:
|
|
58
|
+
data = client.signup(email, password)
|
|
59
|
+
user = data.get("user") or data
|
|
60
|
+
result.ok = True
|
|
61
|
+
result.user_id = user.get("id")
|
|
62
|
+
result.access_token = data.get("access_token")
|
|
63
|
+
result.session_user = user if isinstance(user, dict) else data
|
|
64
|
+
|
|
65
|
+
try:
|
|
66
|
+
drops = client.get_unseen_drops()
|
|
67
|
+
result.unseen_drops = drops.data
|
|
68
|
+
except Exception:
|
|
69
|
+
result.unseen_drops = None
|
|
70
|
+
|
|
71
|
+
try:
|
|
72
|
+
crates = client.get_unseen_crates()
|
|
73
|
+
result.unseen_crates = crates.data
|
|
74
|
+
except Exception:
|
|
75
|
+
result.unseen_crates = None
|
|
76
|
+
|
|
77
|
+
try:
|
|
78
|
+
session = client.auth.get_session()
|
|
79
|
+
if session:
|
|
80
|
+
result.session_user = session
|
|
81
|
+
except Exception:
|
|
82
|
+
pass
|
|
83
|
+
|
|
84
|
+
except AuthError as e:
|
|
85
|
+
result.error = e.message
|
|
86
|
+
except JugsError as e:
|
|
87
|
+
result.error = e.message
|
|
88
|
+
except Exception as e:
|
|
89
|
+
result.error = str(e)
|
|
90
|
+
|
|
91
|
+
return result
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def render_header() -> None:
|
|
95
|
+
title = Text()
|
|
96
|
+
title.append("jugs", style="bold magenta")
|
|
97
|
+
title.append(" multi-account forge", style="bold white")
|
|
98
|
+
|
|
99
|
+
console.print()
|
|
100
|
+
console.print(Panel(
|
|
101
|
+
Align.center(title),
|
|
102
|
+
subtitle="[dim]create · inspect · display[/dim]",
|
|
103
|
+
border_style="magenta",
|
|
104
|
+
box=box.DOUBLE,
|
|
105
|
+
))
|
|
106
|
+
console.print()
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def render_account(idx: int, acc: AccountResult) -> None:
|
|
110
|
+
status = Text("SUCCESS", style="bold green") if acc.ok else Text("FAILED", style="bold red")
|
|
111
|
+
|
|
112
|
+
table = Table(
|
|
113
|
+
show_header=False,
|
|
114
|
+
box=box.ROUNDED,
|
|
115
|
+
border_style="cyan" if acc.ok else "red",
|
|
116
|
+
padding=(0, 1),
|
|
117
|
+
expand=True,
|
|
118
|
+
)
|
|
119
|
+
table.add_column("key", style="bold dim", width=16)
|
|
120
|
+
table.add_column("value", overflow="fold")
|
|
121
|
+
|
|
122
|
+
table.add_row("status", status)
|
|
123
|
+
table.add_row("email", f"[bold]{acc.email}[/bold]")
|
|
124
|
+
table.add_row("password", f"[yellow]{acc.password}[/yellow]")
|
|
125
|
+
|
|
126
|
+
if acc.user_id:
|
|
127
|
+
table.add_row("user id", f"[cyan]{acc.user_id}[/cyan]")
|
|
128
|
+
|
|
129
|
+
if acc.access_token:
|
|
130
|
+
token_preview = acc.access_token[:28] + "…" if len(acc.access_token) > 28 else acc.access_token
|
|
131
|
+
table.add_row("access token", f"[dim]{token_preview}[/dim]")
|
|
132
|
+
|
|
133
|
+
if acc.session_user:
|
|
134
|
+
email_confirmed = acc.session_user.get("email_confirmed_at")
|
|
135
|
+
created = acc.session_user.get("created_at", "?")
|
|
136
|
+
table.add_row("created", str(created))
|
|
137
|
+
table.add_row("email confirmed", "yes" if email_confirmed else "[yellow]pending[/yellow]")
|
|
138
|
+
|
|
139
|
+
meta = acc.session_user.get("user_metadata") or {}
|
|
140
|
+
if meta:
|
|
141
|
+
table.add_row("metadata", str(meta))
|
|
142
|
+
|
|
143
|
+
if acc.unseen_drops is not None:
|
|
144
|
+
table.add_row("unseen drops", f"[green]{acc.unseen_drops}[/green]")
|
|
145
|
+
|
|
146
|
+
if acc.unseen_crates is not None:
|
|
147
|
+
table.add_row("unseen crates", f"[green]{acc.unseen_crates}[/green]")
|
|
148
|
+
|
|
149
|
+
if acc.error:
|
|
150
|
+
table.add_row("error", f"[red]{acc.error}[/red]")
|
|
151
|
+
|
|
152
|
+
console.print(Panel(
|
|
153
|
+
table,
|
|
154
|
+
title=f"[bold]Account {idx}[/bold]",
|
|
155
|
+
border_style="cyan" if acc.ok else "red",
|
|
156
|
+
box=box.ROUNDED,
|
|
157
|
+
))
|
|
158
|
+
console.print()
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def render_summary(results: list[AccountResult]) -> None:
|
|
162
|
+
ok_count = sum(1 for r in results if r.ok)
|
|
163
|
+
fail_count = len(results) - ok_count
|
|
164
|
+
|
|
165
|
+
summary = Table(box=box.SIMPLE_HEAVY, show_header=True, border_style="magenta")
|
|
166
|
+
summary.add_column("metric", style="bold")
|
|
167
|
+
summary.add_column("value", justify="right")
|
|
168
|
+
|
|
169
|
+
summary.add_row("total", str(len(results)))
|
|
170
|
+
summary.add_row("success", f"[green]{ok_count}[/green]")
|
|
171
|
+
summary.add_row("failed", f"[red]{fail_count}[/red]")
|
|
172
|
+
|
|
173
|
+
console.print(Rule("[bold magenta]summary[/bold magenta]"))
|
|
174
|
+
console.print(summary)
|
|
175
|
+
console.print()
|
|
176
|
+
|
|
177
|
+
if ok_count:
|
|
178
|
+
creds = Table(title="credentials", box=box.MINIMAL_DOUBLE_HEAD, border_style="green")
|
|
179
|
+
creds.add_column("#", style="dim")
|
|
180
|
+
creds.add_column("email", style="bold")
|
|
181
|
+
creds.add_column("password", style="yellow")
|
|
182
|
+
creds.add_column("user id", style="cyan")
|
|
183
|
+
|
|
184
|
+
for i, r in enumerate(results, 1):
|
|
185
|
+
if r.ok:
|
|
186
|
+
creds.add_row(str(i), r.email, r.password, r.user_id or "—")
|
|
187
|
+
|
|
188
|
+
console.print(creds)
|
|
189
|
+
console.print()
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def main() -> None:
|
|
193
|
+
count = 3
|
|
194
|
+
if len(sys.argv) > 1:
|
|
195
|
+
try:
|
|
196
|
+
count = max(1, int(sys.argv[1]))
|
|
197
|
+
except ValueError:
|
|
198
|
+
pass
|
|
199
|
+
|
|
200
|
+
render_header()
|
|
201
|
+
|
|
202
|
+
results: list[AccountResult] = []
|
|
203
|
+
|
|
204
|
+
with Progress(
|
|
205
|
+
SpinnerColumn(style="magenta"),
|
|
206
|
+
TextColumn("[progress.description]{task.description}"),
|
|
207
|
+
BarColumn(bar_width=24, style="cyan", complete_style="green"),
|
|
208
|
+
console=console,
|
|
209
|
+
transient=True,
|
|
210
|
+
) as progress:
|
|
211
|
+
task = progress.add_task("forging accounts…", total=count)
|
|
212
|
+
|
|
213
|
+
for i in range(count):
|
|
214
|
+
email, password = generate_account()
|
|
215
|
+
progress.update(task, description=f"creating [cyan]{email}[/cyan]")
|
|
216
|
+
|
|
217
|
+
with JugsClient("c") as client:
|
|
218
|
+
result = create_account(client, email, password)
|
|
219
|
+
|
|
220
|
+
results.append(result)
|
|
221
|
+
progress.advance(task)
|
|
222
|
+
time.sleep(0.4)
|
|
223
|
+
|
|
224
|
+
console.print()
|
|
225
|
+
console.print(Rule("[bold]results[/bold]"))
|
|
226
|
+
console.print()
|
|
227
|
+
|
|
228
|
+
for i, acc in enumerate(results, 1):
|
|
229
|
+
render_account(i, acc)
|
|
230
|
+
|
|
231
|
+
render_summary(results)
|
|
232
|
+
|
|
233
|
+
console.print(Panel(
|
|
234
|
+
Align.center("[dim]done — accounts created via Supabase Auth on jugs.lol[/dim]"),
|
|
235
|
+
border_style="dim",
|
|
236
|
+
box=box.SIMPLE,
|
|
237
|
+
))
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
if __name__ == "__main__":
|
|
241
|
+
main()
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from jugs import JugsClient
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
PROXIES = [
|
|
5
|
+
"http://user:pass@ip1:port",
|
|
6
|
+
"http://user:pass@ip2:port",
|
|
7
|
+
]
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def main() -> None:
|
|
11
|
+
with JugsClient("c", proxies=PROXIES) as client:
|
|
12
|
+
for _ in range(5):
|
|
13
|
+
result = client.view(rotate=True)
|
|
14
|
+
print(result)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
if __name__ == "__main__":
|
|
18
|
+
main()
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from jugs.client import JugsClient
|
|
4
|
+
from jugs.exceptions import (
|
|
5
|
+
AuthError,
|
|
6
|
+
JugsError,
|
|
7
|
+
NotFoundError,
|
|
8
|
+
ProxyError,
|
|
9
|
+
RateLimitError,
|
|
10
|
+
ValidationError,
|
|
11
|
+
)
|
|
12
|
+
from jugs.models import (
|
|
13
|
+
ActionResult,
|
|
14
|
+
ClickResult,
|
|
15
|
+
Comment,
|
|
16
|
+
CommentsResult,
|
|
17
|
+
DiscordMember,
|
|
18
|
+
DiscordUser,
|
|
19
|
+
PresenceResult,
|
|
20
|
+
StatusResult,
|
|
21
|
+
ViewResult,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
__all__ = (
|
|
25
|
+
"JugsClient",
|
|
26
|
+
"JugsError",
|
|
27
|
+
"AuthError",
|
|
28
|
+
"RateLimitError",
|
|
29
|
+
"NotFoundError",
|
|
30
|
+
"ValidationError",
|
|
31
|
+
"ProxyError",
|
|
32
|
+
"ViewResult",
|
|
33
|
+
"StatusResult",
|
|
34
|
+
"Comment",
|
|
35
|
+
"CommentsResult",
|
|
36
|
+
"DiscordUser",
|
|
37
|
+
"DiscordMember",
|
|
38
|
+
"PresenceResult",
|
|
39
|
+
"ClickResult",
|
|
40
|
+
"ActionResult",
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
__version__ = "1.0.0"
|