Refactor cookie handling and service structure

- Removed the old CookieResult model from pyfragment.core.models and created a new one in pyfragment.services.cookies.models.
- Implemented get_cookies_from_browser function in pyfragment.services.cookies.service to extract cookies directly from supported browsers.
- Updated imports across various modules to reflect the new structure and removed unused imports.
- Cleaned up models in ads, anonymous_numbers, giveaways, marketplace, and purchases domains by removing unnecessary __all__ declarations.
- Added new example scripts for cookie extraction and various purchase functionalities.
- Consolidated constants into a new pyfragment.core.constants module for better organization.
This commit is contained in:
bohd4nx
2026-06-16 01:19:33 +03:00
parent 9f11ccb3ee
commit dc9661134d
51 changed files with 178 additions and 234 deletions
+4 -9
View File
@@ -38,8 +38,10 @@ pip install git+https://github.com/bohd4nx/pyfragment.git@dev
```python ```python
import asyncio import asyncio
from pyfragment import FragmentClient from pyfragment import FragmentClient
from pyfragment.models.enums import PaymentMethod from pyfragment.enums import PaymentMethod
async def main() -> None: async def main() -> None:
async with FragmentClient( async with FragmentClient(
@@ -58,14 +60,7 @@ async def main() -> None:
recipient = "https://t.me/username" # also: @username, username recipient = "https://t.me/username" # also: @username, username
stars = await client.purchase_stars(recipient, amount=500, payment_method=PaymentMethod.USDT_GRAM) stars = await client.purchase_stars(recipient, amount=500, payment_method=PaymentMethod.USDT_GRAM)
if stars.auto_paid: print(f"Sent {stars.amount} Stars to {stars.username} | tx: {stars.transaction_id}")
print(f"Sent {stars.amount} Stars to {stars.username} | tx: {stars.transaction_id}")
else:
print(f"Manual payment required for {stars.username}")
print(f"Address: {stars.payment_address}")
print(f"Amount: {stars.payment_amount}")
print(f"Expires: {stars.payment_expires_at}")
print(f"QR link: {stars.payment_qr_link}")
premium = await client.purchase_premium(recipient, months=6, payment_method=PaymentMethod.GRAM) premium = await client.purchase_premium(recipient, months=6, payment_method=PaymentMethod.GRAM)
print(f"Sent Premium {premium.amount}m to {premium.username} | tx: {premium.transaction_id}") print(f"Sent Premium {premium.amount}m to {premium.username} | tx: {premium.transaction_id}")
+33
View File
@@ -0,0 +1,33 @@
"""
Example: extract Fragment cookies directly from your browser.
get_cookies_from_browser() reads the Fragment session cookies from a locally
installed browser — no manual copy-paste required.
Supported browsers: arc, brave, chrome, chromium, chromium_based, edge,
firefox, firefox_based, librewolf, opera, opera_gx,
safari, vivaldi.
The returned CookieResult.cookies dict can be passed directly to FragmentClient.
"""
from pyfragment import CookieError, get_cookies_from_browser
def main() -> None:
try:
result = get_cookies_from_browser("chrome") # or "firefox", "edge", "brave", ...
except CookieError as e:
print(f"Could not read cookies: {e}")
return
print(f"Cookies expire: {result.expires}")
print(f"Keys found: {list(result.cookies.keys())}")
# Pass the extracted cookies directly to FragmentClient
# async with FragmentClient(seed=SEED, api_key=API_KEY, cookies=result.cookies) as client:
# ...
if __name__ == "__main__":
main()
+8 -9
View File
@@ -2,7 +2,13 @@ import logging
from importlib.metadata import version from importlib.metadata import version
from pyfragment.client import FragmentClient from pyfragment.client import FragmentClient
from pyfragment.core.cookies import get_cookies_from_browser from pyfragment.domains.ads.models import AdsRechargeResult, AdsTopupResult
from pyfragment.domains.anonymous_numbers.models import LoginCodeResult, TerminateSessionsResult
from pyfragment.domains.giveaways.models import PremiumGiveawayResult, StarsGiveawayResult
from pyfragment.domains.marketplace.models import GiftsResult, NumbersResult, UsernamesResult
from pyfragment.domains.purchases.models import PremiumResult, StarsResult
from pyfragment.domains.tonapi.models import WalletInfo
from pyfragment.enums import PaymentMethod, WalletVersion
from pyfragment.exceptions import ( from pyfragment.exceptions import (
AlreadySubscribedError, AlreadySubscribedError,
AnonymousNumberError, AnonymousNumberError,
@@ -20,14 +26,7 @@ from pyfragment.exceptions import (
VerificationError, VerificationError,
WalletError, WalletError,
) )
from pyfragment.domains.anonymous_numbers.models import LoginCodeResult, TerminateSessionsResult from pyfragment.services.cookies import CookieResult, get_cookies_from_browser
from pyfragment.core.models import CookieResult
from pyfragment.enums import PaymentMethod, WalletVersion
from pyfragment.domains.giveaways.models import PremiumGiveawayResult, StarsGiveawayResult
from pyfragment.domains.marketplace.models import GiftsResult, NumbersResult, UsernamesResult
from pyfragment.domains.ads.models import AdsRechargeResult, AdsTopupResult
from pyfragment.domains.purchases.models import PremiumResult, StarsResult
from pyfragment.domains.tonapi.models import WalletInfo
logging.getLogger("pyfragment").addHandler(logging.NullHandler()) logging.getLogger("pyfragment").addHandler(logging.NullHandler())
+8 -8
View File
@@ -11,21 +11,21 @@ from pyfragment.core.constants import (
REQUIRED_COOKIE_KEYS, REQUIRED_COOKIE_KEYS,
TONAPI_KEY_MIN_LENGTH, TONAPI_KEY_MIN_LENGTH,
) )
from pyfragment.domains.ads.models import AdsRechargeResult, AdsTopupResult
from pyfragment.domains.ads.service import AdsService from pyfragment.domains.ads.service import AdsService
from pyfragment.domains.anonymous_numbers.models import LoginCodeResult, TerminateSessionsResult
from pyfragment.domains.anonymous_numbers.service import AnonymousNumbersService from pyfragment.domains.anonymous_numbers.service import AnonymousNumbersService
from pyfragment.domains.base import raw_api_call from pyfragment.domains.base import raw_api_call
from pyfragment.domains.giveaways.service import GiveawaysService
from pyfragment.domains.marketplace.service import MarketplaceService
from pyfragment.domains.purchases.service import PurchasesService
from pyfragment.domains.tonapi.service import TonapiService
from pyfragment.exceptions import ConfigurationError, CookieError
from pyfragment.domains.anonymous_numbers.models import LoginCodeResult, TerminateSessionsResult
from pyfragment.enums import PaymentMethod, WalletVersion
from pyfragment.domains.giveaways.models import PremiumGiveawayResult, StarsGiveawayResult from pyfragment.domains.giveaways.models import PremiumGiveawayResult, StarsGiveawayResult
from pyfragment.domains.giveaways.service import GiveawaysService
from pyfragment.domains.marketplace.models import GiftsResult, NumbersResult, UsernamesResult from pyfragment.domains.marketplace.models import GiftsResult, NumbersResult, UsernamesResult
from pyfragment.domains.ads.models import AdsRechargeResult, AdsTopupResult from pyfragment.domains.marketplace.service import MarketplaceService
from pyfragment.domains.purchases.models import PremiumResult, StarsResult from pyfragment.domains.purchases.models import PremiumResult, StarsResult
from pyfragment.domains.purchases.service import PurchasesService
from pyfragment.domains.tonapi.models import WalletInfo from pyfragment.domains.tonapi.models import WalletInfo
from pyfragment.domains.tonapi.service import TonapiService
from pyfragment.enums import PaymentMethod, WalletVersion
from pyfragment.exceptions import ConfigurationError, CookieError
class FragmentClient: class FragmentClient:
+87
View File
@@ -0,0 +1,87 @@
from __future__ import annotations
from typing import Any
FRAGMENT_DOMAIN: str = "fragment.com"
FRAGMENT_BASE_URL: str = f"https://{FRAGMENT_DOMAIN}"
STARS_PAGE: str = f"{FRAGMENT_BASE_URL}/stars/buy"
STARS_GIVEAWAY_PAGE: str = f"{FRAGMENT_BASE_URL}/stars/giveaway"
PREMIUM_PAGE: str = f"{FRAGMENT_BASE_URL}/premium/gift"
PREMIUM_GIVEAWAY_PAGE: str = f"{FRAGMENT_BASE_URL}/premium/giveaway"
ADS_TOPUP_PAGE: str = f"{FRAGMENT_BASE_URL}/ads/topup"
NUMBERS_PAGE: str = f"{FRAGMENT_BASE_URL}/numbers"
GIFTS_PAGE: str = f"{FRAGMENT_BASE_URL}/gifts"
DEFAULT_TIMEOUT: float = 30.0
# Fragment cookie keys required for authenticated API calls
REQUIRED_COOKIE_KEYS: tuple[str, ...] = ("stel_ssid", "stel_dt", "stel_token", "stel_ton_token")
BASE_HEADERS: dict[str, str] = {
"accept": "application/json, text/javascript, */*; q=0.01",
"accept-language": "en-US,en;q=0.9,uk;q=0.8,ru;q=0.7",
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
"origin": FRAGMENT_BASE_URL,
"priority": "u=1, i",
"sec-ch-ua": '"Google Chrome";v="147", "Not.A/Brand";v="8", "Chromium";v="147"',
"sec-ch-ua-mobile": "?1",
"sec-ch-ua-platform": '"Android"',
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin",
"user-agent": (
"Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) "
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Mobile Safari/537.36"
),
"x-requested-with": "XMLHttpRequest",
}
# USDT-TON jetton master contract address on GRAM (ex TON) mainnet
USDT_GRAM_MASTER_ADDRESS: str = "EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs"
# TON Connect device info sent during wallet connection handshake
DEVICE_INFO: dict[str, Any] = {
"platform": "iphone",
"appName": "Tonkeeper",
"appVersion": "26.05.0",
"maxProtocolVersion": 2,
"features": [
"SendTransaction",
{"name": "SendTransaction", "maxMessages": 255},
{"name": "SignData", "types": ["text", "binary", "cell"]},
],
}
# Stars: direct purchase per transaction
STARS_PURCHASE_MIN: int = 50
STARS_PURCHASE_MAX: int = 10_000_000
# Stars: giveaway amount per winner
STARS_GIVEAWAY_MIN: int = 500
STARS_GIVEAWAY_MAX: int = 1_000_000
# Stars giveaway winner count
STARS_WINNERS_MIN: int = 1
STARS_WINNERS_MAX: int = 15
# Premium giveaway winner count
PREMIUM_WINNERS_MIN: int = 1
PREMIUM_WINNERS_MAX: int = 24_000
# GRAM (ex TON) topup / Ads recharge amount
GRAM_TOPUP_MIN: int = 1
GRAM_TOPUP_MAX: int = 1_000_000_000
# Minimum wallet balances required before broadcasting a transaction
MIN_GRAM_BALANCE: float = 0.33
MIN_USDT_BALANCE: float = 0.75
# Premium subscription durations (months)
PREMIUM_MONTHS_VALID: frozenset[int] = frozenset({3, 6, 12})
# Mnemonic phrase valid word counts
MNEMONIC_WORD_COUNTS_VALID: frozenset[int] = frozenset({12, 24})
# Tonapi API key minimum length (tonapi.io)
TONAPI_KEY_MIN_LENGTH: int = 68
-64
View File
@@ -1,64 +0,0 @@
from __future__ import annotations
from pyfragment.core.constants.gram import DEVICE_INFO, USDT_GRAM_MASTER_ADDRESS
from pyfragment.core.constants.headers import BASE_HEADERS, DEFAULT_TIMEOUT, REQUIRED_COOKIE_KEYS
from pyfragment.core.constants.limits import (
GRAM_TOPUP_MAX,
GRAM_TOPUP_MIN,
MIN_GRAM_BALANCE,
MIN_USDT_BALANCE,
MNEMONIC_WORD_COUNTS_VALID,
PREMIUM_MONTHS_VALID,
PREMIUM_WINNERS_MAX,
PREMIUM_WINNERS_MIN,
STARS_GIVEAWAY_MAX,
STARS_GIVEAWAY_MIN,
STARS_PURCHASE_MAX,
STARS_PURCHASE_MIN,
STARS_WINNERS_MAX,
STARS_WINNERS_MIN,
TONAPI_KEY_MIN_LENGTH,
)
from pyfragment.core.constants.urls import (
ADS_TOPUP_PAGE,
FRAGMENT_BASE_URL,
FRAGMENT_DOMAIN,
GIFTS_PAGE,
NUMBERS_PAGE,
PREMIUM_GIVEAWAY_PAGE,
PREMIUM_PAGE,
STARS_GIVEAWAY_PAGE,
STARS_PAGE,
)
__all__ = [
"ADS_TOPUP_PAGE",
"BASE_HEADERS",
"DEFAULT_TIMEOUT",
"DEVICE_INFO",
"FRAGMENT_BASE_URL",
"FRAGMENT_DOMAIN",
"GIFTS_PAGE",
"GRAM_TOPUP_MAX",
"GRAM_TOPUP_MIN",
"MIN_GRAM_BALANCE",
"MIN_USDT_BALANCE",
"MNEMONIC_WORD_COUNTS_VALID",
"NUMBERS_PAGE",
"PREMIUM_GIVEAWAY_PAGE",
"PREMIUM_MONTHS_VALID",
"PREMIUM_PAGE",
"PREMIUM_WINNERS_MAX",
"PREMIUM_WINNERS_MIN",
"REQUIRED_COOKIE_KEYS",
"STARS_GIVEAWAY_MAX",
"STARS_GIVEAWAY_MIN",
"STARS_GIVEAWAY_PAGE",
"STARS_PAGE",
"STARS_PURCHASE_MAX",
"STARS_PURCHASE_MIN",
"STARS_WINNERS_MAX",
"STARS_WINNERS_MIN",
"TONAPI_KEY_MIN_LENGTH",
"USDT_GRAM_MASTER_ADDRESS",
]
-17
View File
@@ -1,17 +0,0 @@
from __future__ import annotations
from typing import Any
USDT_GRAM_MASTER_ADDRESS: str = "EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs"
DEVICE_INFO: dict[str, Any] = {
"platform": "iphone",
"appName": "Tonkeeper",
"appVersion": "26.05.0",
"maxProtocolVersion": 2,
"features": [
"SendTransaction",
{"name": "SendTransaction", "maxMessages": 255},
{"name": "SignData", "types": ["text", "binary", "cell"]},
],
}
-26
View File
@@ -1,26 +0,0 @@
from __future__ import annotations
from pyfragment.core.constants.urls import FRAGMENT_BASE_URL
DEFAULT_TIMEOUT: float = 30.0
REQUIRED_COOKIE_KEYS: tuple[str, ...] = ("stel_ssid", "stel_dt", "stel_token", "stel_ton_token")
BASE_HEADERS: dict[str, str] = {
"accept": "application/json, text/javascript, */*; q=0.01",
"accept-language": "en-US,en;q=0.9,uk;q=0.8,ru;q=0.7",
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
"origin": FRAGMENT_BASE_URL,
"priority": "u=1, i",
"sec-ch-ua": '"Google Chrome";v="147", "Not.A/Brand";v="8", "Chromium";v="147"',
"sec-ch-ua-mobile": "?1",
"sec-ch-ua-platform": '"Android"',
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin",
"user-agent": (
"Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) "
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Mobile Safari/537.36"
),
"x-requested-with": "XMLHttpRequest",
}
-34
View File
@@ -1,34 +0,0 @@
from __future__ import annotations
# Stars: direct purchase
STARS_PURCHASE_MIN: int = 50
STARS_PURCHASE_MAX: int = 10_000_000
# Stars: giveaway per winner
STARS_GIVEAWAY_MIN: int = 500
STARS_GIVEAWAY_MAX: int = 1_000_000
# Stars giveaway winners count
STARS_WINNERS_MIN: int = 1
STARS_WINNERS_MAX: int = 15
# Premium giveaway winners count
PREMIUM_WINNERS_MIN: int = 1
PREMIUM_WINNERS_MAX: int = 24_000
# GRAM (ex TON) topup / Ads recharge amount
GRAM_TOPUP_MIN: int = 1
GRAM_TOPUP_MAX: int = 1_000_000_000
# Wallet minimum balances
MIN_GRAM_BALANCE: float = 0.33
MIN_USDT_BALANCE: float = 0.75
# Premium subscription durations (months)
PREMIUM_MONTHS_VALID: frozenset[int] = frozenset({3, 6, 12})
# Mnemonic phrase valid word counts
MNEMONIC_WORD_COUNTS_VALID: frozenset[int] = frozenset({12, 24})
# Tonapi API key minimum length
TONAPI_KEY_MIN_LENGTH: int = 68
-12
View File
@@ -1,12 +0,0 @@
from __future__ import annotations
FRAGMENT_DOMAIN: str = "fragment.com"
FRAGMENT_BASE_URL: str = f"https://{FRAGMENT_DOMAIN}"
STARS_PAGE: str = f"{FRAGMENT_BASE_URL}/stars/buy"
STARS_GIVEAWAY_PAGE: str = f"{FRAGMENT_BASE_URL}/stars/giveaway"
PREMIUM_PAGE: str = f"{FRAGMENT_BASE_URL}/premium/gift"
PREMIUM_GIVEAWAY_PAGE: str = f"{FRAGMENT_BASE_URL}/premium/giveaway"
ADS_TOPUP_PAGE: str = f"{FRAGMENT_BASE_URL}/ads/topup"
NUMBERS_PAGE: str = f"{FRAGMENT_BASE_URL}/numbers"
GIFTS_PAGE: str = f"{FRAGMENT_BASE_URL}/gifts"
-3
View File
@@ -20,6 +20,3 @@ class AdsRechargeResult:
def __repr__(self) -> str: def __repr__(self) -> str:
return f"AdsRechargeResult(amount={self.amount} GRAM (ex TON), tx='{self.transaction_id}')" return f"AdsRechargeResult(amount={self.amount} GRAM (ex TON), tx='{self.transaction_id}')"
__all__ = ["AdsRechargeResult", "AdsTopupResult"]
+1 -1
View File
@@ -5,10 +5,10 @@ import logging
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from pyfragment.core.constants import ADS_TOPUP_PAGE, DEVICE_INFO, GRAM_TOPUP_MAX, GRAM_TOPUP_MIN from pyfragment.core.constants import ADS_TOPUP_PAGE, DEVICE_INFO, GRAM_TOPUP_MAX, GRAM_TOPUP_MIN
from pyfragment.domains.ads.models import AdsRechargeResult
from pyfragment.domains.tonapi.account import get_account_info from pyfragment.domains.tonapi.account import get_account_info
from pyfragment.domains.tonapi.transaction import process_transaction from pyfragment.domains.tonapi.transaction import process_transaction
from pyfragment.exceptions import ConfigurationError, FragmentAPIError, FragmentError, UnexpectedError, VerificationError from pyfragment.exceptions import ConfigurationError, FragmentAPIError, FragmentError, UnexpectedError, VerificationError
from pyfragment.domains.ads.models import AdsRechargeResult
if TYPE_CHECKING: if TYPE_CHECKING:
from pyfragment.client import FragmentClient from pyfragment.client import FragmentClient
+1 -1
View File
@@ -2,10 +2,10 @@ from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from pyfragment.domains.ads.models import AdsRechargeResult, AdsTopupResult
from pyfragment.domains.ads.recharge import recharge_ads from pyfragment.domains.ads.recharge import recharge_ads
from pyfragment.domains.ads.tonup import topup_gram from pyfragment.domains.ads.tonup import topup_gram
from pyfragment.domains.base import BaseService from pyfragment.domains.base import BaseService
from pyfragment.domains.ads.models import AdsRechargeResult, AdsTopupResult
if TYPE_CHECKING: if TYPE_CHECKING:
pass pass
+1 -1
View File
@@ -5,6 +5,7 @@ import logging
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from pyfragment.core.constants import ADS_TOPUP_PAGE, DEVICE_INFO, GRAM_TOPUP_MAX, GRAM_TOPUP_MIN from pyfragment.core.constants import ADS_TOPUP_PAGE, DEVICE_INFO, GRAM_TOPUP_MAX, GRAM_TOPUP_MIN
from pyfragment.domains.ads.models import AdsTopupResult
from pyfragment.domains.payments import parse_required_payment_amount from pyfragment.domains.payments import parse_required_payment_amount
from pyfragment.domains.tonapi.account import get_account_info from pyfragment.domains.tonapi.account import get_account_info
from pyfragment.domains.tonapi.transaction import process_transaction from pyfragment.domains.tonapi.transaction import process_transaction
@@ -16,7 +17,6 @@ from pyfragment.exceptions import (
UserNotFoundError, UserNotFoundError,
VerificationError, VerificationError,
) )
from pyfragment.domains.ads.models import AdsTopupResult
if TYPE_CHECKING: if TYPE_CHECKING:
from pyfragment.client import FragmentClient from pyfragment.client import FragmentClient
@@ -1,6 +1,6 @@
from pyfragment.domains.anonymous_numbers.models import LoginCodeResult, TerminateSessionsResult
from pyfragment.domains.anonymous_numbers.number import get_login_code, terminate_sessions, toggle_login_codes from pyfragment.domains.anonymous_numbers.number import get_login_code, terminate_sessions, toggle_login_codes
from pyfragment.domains.anonymous_numbers.service import AnonymousNumbersService from pyfragment.domains.anonymous_numbers.service import AnonymousNumbersService
from pyfragment.domains.anonymous_numbers.models import LoginCodeResult, TerminateSessionsResult
__all__ = [ __all__ = [
"AnonymousNumbersService", "AnonymousNumbersService",
@@ -21,6 +21,3 @@ class TerminateSessionsResult:
def __repr__(self) -> str: def __repr__(self) -> str:
return f"TerminateSessionsResult(number='{self.number}', message={self.message!r})" return f"TerminateSessionsResult(number='{self.number}', message={self.message!r})"
__all__ = ["LoginCodeResult", "TerminateSessionsResult"]
@@ -5,9 +5,9 @@ import logging
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from pyfragment.core.constants import NUMBERS_PAGE from pyfragment.core.constants import NUMBERS_PAGE
from pyfragment.domains.anonymous_numbers.models import LoginCodeResult, TerminateSessionsResult
from pyfragment.domains.anonymous_numbers.parser import parse_login_code from pyfragment.domains.anonymous_numbers.parser import parse_login_code
from pyfragment.exceptions import AnonymousNumberError, FragmentAPIError, FragmentError, UnexpectedError from pyfragment.exceptions import AnonymousNumberError, FragmentAPIError, FragmentError, UnexpectedError
from pyfragment.domains.anonymous_numbers.models import LoginCodeResult, TerminateSessionsResult
if TYPE_CHECKING: if TYPE_CHECKING:
from pyfragment.client import FragmentClient from pyfragment.client import FragmentClient
@@ -2,9 +2,9 @@ from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from pyfragment.domains.anonymous_numbers.models import LoginCodeResult, TerminateSessionsResult
from pyfragment.domains.anonymous_numbers.number import get_login_code, terminate_sessions, toggle_login_codes from pyfragment.domains.anonymous_numbers.number import get_login_code, terminate_sessions, toggle_login_codes
from pyfragment.domains.base import BaseService from pyfragment.domains.base import BaseService
from pyfragment.domains.anonymous_numbers.models import LoginCodeResult, TerminateSessionsResult
if TYPE_CHECKING: if TYPE_CHECKING:
pass pass
+1 -1
View File
@@ -1,6 +1,6 @@
from pyfragment.domains.giveaways.giveaway import giveaway_premium, giveaway_stars from pyfragment.domains.giveaways.giveaway import giveaway_premium, giveaway_stars
from pyfragment.domains.giveaways.service import GiveawaysService
from pyfragment.domains.giveaways.models import PremiumGiveawayResult, StarsGiveawayResult from pyfragment.domains.giveaways.models import PremiumGiveawayResult, StarsGiveawayResult
from pyfragment.domains.giveaways.service import GiveawaysService
__all__ = [ __all__ = [
"GiveawaysService", "GiveawaysService",
+2 -2
View File
@@ -17,9 +17,11 @@ from pyfragment.core.constants import (
STARS_WINNERS_MAX, STARS_WINNERS_MAX,
STARS_WINNERS_MIN, STARS_WINNERS_MIN,
) )
from pyfragment.domains.giveaways.models import PremiumGiveawayResult, StarsGiveawayResult
from pyfragment.domains.payments import parse_required_payment_amount from pyfragment.domains.payments import parse_required_payment_amount
from pyfragment.domains.tonapi.account import get_account_info from pyfragment.domains.tonapi.account import get_account_info
from pyfragment.domains.tonapi.transaction import process_transaction from pyfragment.domains.tonapi.transaction import process_transaction
from pyfragment.enums import PaymentMethod
from pyfragment.exceptions import ( from pyfragment.exceptions import (
ConfigurationError, ConfigurationError,
FragmentAPIError, FragmentAPIError,
@@ -28,8 +30,6 @@ from pyfragment.exceptions import (
UserNotFoundError, UserNotFoundError,
VerificationError, VerificationError,
) )
from pyfragment.enums import PaymentMethod
from pyfragment.domains.giveaways.models import PremiumGiveawayResult, StarsGiveawayResult
if TYPE_CHECKING: if TYPE_CHECKING:
from pyfragment.client import FragmentClient from pyfragment.client import FragmentClient
-3
View File
@@ -29,6 +29,3 @@ class PremiumGiveawayResult:
f"PremiumGiveawayResult(channel='{self.channel}', winners={self.winners}, " f"PremiumGiveawayResult(channel='{self.channel}', winners={self.winners}, "
f"amount={self.amount} months per winner, tx='{self.transaction_id}')" f"amount={self.amount} months per winner, tx='{self.transaction_id}')"
) )
__all__ = ["PremiumGiveawayResult", "StarsGiveawayResult"]
+1 -1
View File
@@ -4,8 +4,8 @@ from typing import TYPE_CHECKING
from pyfragment.domains.base import BaseService from pyfragment.domains.base import BaseService
from pyfragment.domains.giveaways.giveaway import giveaway_premium, giveaway_stars from pyfragment.domains.giveaways.giveaway import giveaway_premium, giveaway_stars
from pyfragment.enums import PaymentMethod
from pyfragment.domains.giveaways.models import PremiumGiveawayResult, StarsGiveawayResult from pyfragment.domains.giveaways.models import PremiumGiveawayResult, StarsGiveawayResult
from pyfragment.enums import PaymentMethod
if TYPE_CHECKING: if TYPE_CHECKING:
pass pass
+1 -1
View File
@@ -1,6 +1,6 @@
from pyfragment.domains.marketplace.models import GiftsResult, NumbersResult, UsernamesResult
from pyfragment.domains.marketplace.search import search_gifts, search_numbers, search_usernames from pyfragment.domains.marketplace.search import search_gifts, search_numbers, search_usernames
from pyfragment.domains.marketplace.service import MarketplaceService from pyfragment.domains.marketplace.service import MarketplaceService
from pyfragment.domains.marketplace.models import GiftsResult, NumbersResult, UsernamesResult
__all__ = [ __all__ = [
"GiftsResult", "GiftsResult",
-3
View File
@@ -29,6 +29,3 @@ class GiftsResult:
def __repr__(self) -> str: def __repr__(self) -> str:
return f"GiftsResult(items={len(self.items)}, next_offset={self.next_offset!r})" return f"GiftsResult(items={len(self.items)}, next_offset={self.next_offset!r})"
__all__ = ["GiftsResult", "NumbersResult", "UsernamesResult"]
+1 -1
View File
@@ -4,9 +4,9 @@ import logging
from typing import TYPE_CHECKING, Any from typing import TYPE_CHECKING, Any
from pyfragment.core.constants import FRAGMENT_BASE_URL, GIFTS_PAGE, NUMBERS_PAGE from pyfragment.core.constants import FRAGMENT_BASE_URL, GIFTS_PAGE, NUMBERS_PAGE
from pyfragment.domains.marketplace.models import GiftsResult, NumbersResult, UsernamesResult
from pyfragment.domains.marketplace.parser import parse_auction_rows, parse_gift_items from pyfragment.domains.marketplace.parser import parse_auction_rows, parse_gift_items
from pyfragment.exceptions import FragmentAPIError, FragmentError, UnexpectedError from pyfragment.exceptions import FragmentAPIError, FragmentError, UnexpectedError
from pyfragment.domains.marketplace.models import GiftsResult, NumbersResult, UsernamesResult
if TYPE_CHECKING: if TYPE_CHECKING:
from pyfragment.client import FragmentClient from pyfragment.client import FragmentClient
+1 -1
View File
@@ -3,8 +3,8 @@ from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from pyfragment.domains.base import BaseService from pyfragment.domains.base import BaseService
from pyfragment.domains.marketplace.search import search_gifts, search_numbers, search_usernames
from pyfragment.domains.marketplace.models import GiftsResult, NumbersResult, UsernamesResult from pyfragment.domains.marketplace.models import GiftsResult, NumbersResult, UsernamesResult
from pyfragment.domains.marketplace.search import search_gifts, search_numbers, search_usernames
if TYPE_CHECKING: if TYPE_CHECKING:
pass pass
+1 -1
View File
@@ -1,5 +1,5 @@
from pyfragment.domains.purchases.models import PremiumResult, StarsResult
from pyfragment.domains.purchases.purchase import purchase_premium, purchase_stars from pyfragment.domains.purchases.purchase import purchase_premium, purchase_stars
from pyfragment.domains.purchases.service import PurchasesService from pyfragment.domains.purchases.service import PurchasesService
from pyfragment.domains.purchases.models import PremiumResult, StarsResult
__all__ = ["PremiumResult", "PurchasesService", "StarsResult", "purchase_premium", "purchase_stars"] __all__ = ["PremiumResult", "PurchasesService", "StarsResult", "purchase_premium", "purchase_stars"]
-3
View File
@@ -21,6 +21,3 @@ class StarsResult:
def __repr__(self) -> str: def __repr__(self) -> str:
return f"StarsResult(username='{self.username}', amount={self.amount} stars, tx='{self.transaction_id}')" return f"StarsResult(username='{self.username}', amount={self.amount} stars, tx='{self.transaction_id}')"
__all__ = ["PremiumResult", "StarsResult"]
+2 -2
View File
@@ -14,8 +14,10 @@ from pyfragment.core.constants import (
STARS_PURCHASE_MIN, STARS_PURCHASE_MIN,
) )
from pyfragment.domains.payments import parse_required_payment_amount from pyfragment.domains.payments import parse_required_payment_amount
from pyfragment.domains.purchases.models import PremiumResult, StarsResult
from pyfragment.domains.tonapi.account import get_account_info from pyfragment.domains.tonapi.account import get_account_info
from pyfragment.domains.tonapi.transaction import process_transaction from pyfragment.domains.tonapi.transaction import process_transaction
from pyfragment.enums import PaymentMethod
from pyfragment.exceptions import ( from pyfragment.exceptions import (
AlreadySubscribedError, AlreadySubscribedError,
ConfigurationError, ConfigurationError,
@@ -25,8 +27,6 @@ from pyfragment.exceptions import (
UserNotFoundError, UserNotFoundError,
VerificationError, VerificationError,
) )
from pyfragment.enums import PaymentMethod
from pyfragment.domains.purchases.models import PremiumResult, StarsResult
if TYPE_CHECKING: if TYPE_CHECKING:
from pyfragment.client import FragmentClient from pyfragment.client import FragmentClient
+1 -1
View File
@@ -3,9 +3,9 @@ from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from pyfragment.domains.base import BaseService from pyfragment.domains.base import BaseService
from pyfragment.domains.purchases.models import PremiumResult, StarsResult
from pyfragment.domains.purchases.purchase import purchase_premium, purchase_stars from pyfragment.domains.purchases.purchase import purchase_premium, purchase_stars
from pyfragment.enums import PaymentMethod from pyfragment.enums import PaymentMethod
from pyfragment.domains.purchases.models import PremiumResult, StarsResult
if TYPE_CHECKING: if TYPE_CHECKING:
pass pass
+2 -2
View File
@@ -10,9 +10,9 @@ from tonutils.contracts.jetton import get_wallet_address_get_method, get_wallet_
from tonutils.exceptions import ProviderResponseError from tonutils.exceptions import ProviderResponseError
from pyfragment.core.constants import MIN_GRAM_BALANCE, MIN_USDT_BALANCE, USDT_GRAM_MASTER_ADDRESS from pyfragment.core.constants import MIN_GRAM_BALANCE, MIN_USDT_BALANCE, USDT_GRAM_MASTER_ADDRESS
from pyfragment.exceptions import WalletError
from pyfragment.enums import WALLET_CLASSES
from pyfragment.domains.tonapi.models import WalletInfo from pyfragment.domains.tonapi.models import WalletInfo
from pyfragment.enums import WALLET_CLASSES
from pyfragment.exceptions import WalletError
if TYPE_CHECKING: if TYPE_CHECKING:
from pyfragment.client import FragmentClient from pyfragment.client import FragmentClient
-3
View File
@@ -15,6 +15,3 @@ class WalletInfo:
f"WalletInfo(address='{self.address}', state='{self.state}', " f"WalletInfo(address='{self.address}', state='{self.state}', "
f"gram_balance={self.gram_balance} GRAM (ex TON), usdt_balance={self.usdt_balance} USDT)" f"gram_balance={self.gram_balance} GRAM (ex TON), usdt_balance={self.usdt_balance} USDT)"
) )
__all__ = ["WalletInfo"]
+1 -1
View File
@@ -12,8 +12,8 @@ from tonutils.clients import TonapiClient
from tonutils.exceptions import ProviderResponseError from tonutils.exceptions import ProviderResponseError
from pyfragment.domains.tonapi.account import check_gram_payment_balance, check_usdt_payment_balance from pyfragment.domains.tonapi.account import check_gram_payment_balance, check_usdt_payment_balance
from pyfragment.exceptions import ParseError, TransactionError, WalletError
from pyfragment.enums import WALLET_CLASSES, PaymentMethod from pyfragment.enums import WALLET_CLASSES, PaymentMethod
from pyfragment.exceptions import ParseError, TransactionError, WalletError
if TYPE_CHECKING: if TYPE_CHECKING:
from pyfragment.client import FragmentClient from pyfragment.client import FragmentClient
-3
View File
@@ -55,6 +55,3 @@ class SupportedBrowser(StrEnum):
OPERA_GX = "opera_gx" OPERA_GX = "opera_gx"
SAFARI = "safari" SAFARI = "safari"
VIVALDI = "vivaldi" VIVALDI = "vivaldi"
__all__ = ["PaymentMethod", "SupportedBrowser", "WALLET_CLASSES", "WalletVersion"]
+1 -1
View File
@@ -1,6 +1,6 @@
from __future__ import annotations from __future__ import annotations
from pyfragment.core.constants.limits import ( from pyfragment.core.constants import (
GRAM_TOPUP_MAX, GRAM_TOPUP_MAX,
GRAM_TOPUP_MIN, GRAM_TOPUP_MIN,
MNEMONIC_WORD_COUNTS_VALID, MNEMONIC_WORD_COUNTS_VALID,
+3
View File
@@ -0,0 +1,3 @@
from pyfragment.services.cookies import CookieResult, get_cookies_from_browser
__all__ = ["CookieResult", "get_cookies_from_browser"]
+4
View File
@@ -0,0 +1,4 @@
from pyfragment.services.cookies.models import CookieResult
from pyfragment.services.cookies.service import get_cookies_from_browser
__all__ = ["CookieResult", "get_cookies_from_browser"]
@@ -10,6 +10,3 @@ class CookieResult:
def __repr__(self) -> str: def __repr__(self) -> str:
return f"CookieResult(cookies={self.cookies!r}, expires={self.expires!r})" return f"CookieResult(cookies={self.cookies!r}, expires={self.expires!r})"
__all__ = ["CookieResult"]
@@ -5,9 +5,9 @@ from datetime import datetime, timezone
from typing import Any from typing import Any
from pyfragment.core.constants import FRAGMENT_BASE_URL, FRAGMENT_DOMAIN, REQUIRED_COOKIE_KEYS from pyfragment.core.constants import FRAGMENT_BASE_URL, FRAGMENT_DOMAIN, REQUIRED_COOKIE_KEYS
from pyfragment.exceptions import CookieError
from pyfragment.core.models import CookieResult
from pyfragment.enums import SupportedBrowser from pyfragment.enums import SupportedBrowser
from pyfragment.exceptions import CookieError
from pyfragment.services.cookies.models import CookieResult
try: try:
import rookiepy import rookiepy
+1 -1
View File
@@ -106,5 +106,5 @@ ignore_missing_imports = true
[[tool.mypy.overrides]] [[tool.mypy.overrides]]
# rookiepy = None assignment is valid when the package is installed (type: ModuleType) # rookiepy = None assignment is valid when the package is installed (type: ModuleType)
# but mypy on CI (without rookiepy) sees it as Any and flags the comment as unused. # but mypy on CI (without rookiepy) sees it as Any and flags the comment as unused.
module = "pyfragment.core.cookies" module = "pyfragment.services.cookies.service"
warn_unused_ignores = false warn_unused_ignores = false
+1 -1
View File
@@ -5,7 +5,7 @@ import json
import pytest import pytest
from pyfragment import ConfigurationError, CookieError, FragmentClient from pyfragment import ConfigurationError, CookieError, FragmentClient
from pyfragment.core.constants.limits import MNEMONIC_WORD_COUNTS_VALID, TONAPI_KEY_MIN_LENGTH from pyfragment.core.constants import MNEMONIC_WORD_COUNTS_VALID, TONAPI_KEY_MIN_LENGTH
from tests.shared import VALID_API_KEY, VALID_COOKIES, VALID_SEED from tests.shared import VALID_API_KEY, VALID_COOKIES, VALID_SEED
# Client init tests # Client init tests
+1 -1
View File
@@ -7,7 +7,7 @@ import pytest
import pyfragment.domains.giveaways.giveaway as _giveaway_stars_mod import pyfragment.domains.giveaways.giveaway as _giveaway_stars_mod
import pyfragment.domains.purchases.purchase as _purchase_stars_mod import pyfragment.domains.purchases.purchase as _purchase_stars_mod
from pyfragment import ConfigurationError, FragmentClient, StarsGiveawayResult, StarsResult, UserNotFoundError from pyfragment import ConfigurationError, FragmentClient, StarsGiveawayResult, StarsResult, UserNotFoundError
from pyfragment.core.constants.limits import ( from pyfragment.core.constants import (
STARS_GIVEAWAY_MAX, STARS_GIVEAWAY_MAX,
STARS_GIVEAWAY_MIN, STARS_GIVEAWAY_MIN,
STARS_PURCHASE_MAX, STARS_PURCHASE_MAX,
+2 -2
View File
@@ -7,9 +7,9 @@ import pytest
import pyfragment.domains.giveaways.giveaway as _giveaway_premium_mod import pyfragment.domains.giveaways.giveaway as _giveaway_premium_mod
import pyfragment.domains.purchases.purchase as _purchase_premium_mod import pyfragment.domains.purchases.purchase as _purchase_premium_mod
from pyfragment import ConfigurationError, FragmentClient, PremiumGiveawayResult, PremiumResult, UserNotFoundError from pyfragment import ConfigurationError, FragmentClient, PremiumGiveawayResult, PremiumResult, UserNotFoundError
from pyfragment.core.constants.limits import PREMIUM_MONTHS_VALID, PREMIUM_WINNERS_MAX, PREMIUM_WINNERS_MIN from pyfragment.core.constants import PREMIUM_MONTHS_VALID, PREMIUM_WINNERS_MAX, PREMIUM_WINNERS_MIN
from pyfragment.exceptions import AlreadySubscribedError
from pyfragment.enums import PaymentMethod from pyfragment.enums import PaymentMethod
from pyfragment.exceptions import AlreadySubscribedError
from tests.shared import FAKE_ACCOUNT, FAKE_RECIPIENT, FAKE_REQ_ID, FAKE_TRANSACTION, FAKE_TX_HASH from tests.shared import FAKE_ACCOUNT, FAKE_RECIPIENT, FAKE_REQ_ID, FAKE_TRANSACTION, FAKE_TX_HASH
# Premium purchase validation tests # Premium purchase validation tests
+1 -1
View File
@@ -6,7 +6,7 @@ import pytest
import pyfragment.domains.ads.tonup as _topup_gram_mod import pyfragment.domains.ads.tonup as _topup_gram_mod
from pyfragment import AdsTopupResult, ConfigurationError, FragmentClient, UserNotFoundError from pyfragment import AdsTopupResult, ConfigurationError, FragmentClient, UserNotFoundError
from pyfragment.core.constants.limits import GRAM_TOPUP_MAX, GRAM_TOPUP_MIN from pyfragment.core.constants import GRAM_TOPUP_MAX, GRAM_TOPUP_MIN
from tests.shared import FAKE_ACCOUNT, FAKE_RECIPIENT, FAKE_REQ_ID, FAKE_TRANSACTION, FAKE_TX_HASH from tests.shared import FAKE_ACCOUNT, FAKE_RECIPIENT, FAKE_REQ_ID, FAKE_TRANSACTION, FAKE_TX_HASH
# Topup GRAM (ex TON) validation tests # Topup GRAM (ex TON) validation tests
+1 -1
View File
@@ -6,7 +6,7 @@ import pytest
import pyfragment.domains.ads.recharge as _recharge_ads_mod import pyfragment.domains.ads.recharge as _recharge_ads_mod
from pyfragment import AdsRechargeResult, ConfigurationError, FragmentClient from pyfragment import AdsRechargeResult, ConfigurationError, FragmentClient
from pyfragment.core.constants.limits import GRAM_TOPUP_MAX, GRAM_TOPUP_MIN from pyfragment.core.constants import GRAM_TOPUP_MAX, GRAM_TOPUP_MIN
from tests.shared import FAKE_ACCOUNT, FAKE_ADS_ACCOUNT, FAKE_REQ_ID, FAKE_TRANSACTION, FAKE_TX_HASH from tests.shared import FAKE_ACCOUNT, FAKE_ADS_ACCOUNT, FAKE_REQ_ID, FAKE_TRANSACTION, FAKE_TX_HASH
# recharge_ads validation tests # recharge_ads validation tests
+1 -1
View File
@@ -22,7 +22,7 @@ def _mock_rookiepy(jar: list[dict[str, str]] | None = None) -> MagicMock:
return mock return mock
PATCH = "pyfragment.core.cookies.rookiepy" PATCH = "pyfragment.services.cookies.service.rookiepy"
# unsupported browser tests # unsupported browser tests