feat: Enhance Fragment API with improved error handling and clean_decode utility; (#1) update version and dependencies

This commit is contained in:
bohd4nx
2025-11-24 19:52:22 +02:00
parent 49cf8843bc
commit 76473993e2
10 changed files with 112 additions and 231 deletions
+16 -16
View File
@@ -1,7 +1,5 @@
import base64
import logging
import re
import string
import time
import httpx
@@ -9,7 +7,7 @@ from tonutils.client import TonapiClient
from tonutils.wallet import WalletV5R1
from app.core.config import Config
from app.utils import TransactionProcessor, WalletLinker, ApiClient
from app.utils import TransactionProcessor, WalletLinker, ApiClient, clean_decode
logger = logging.getLogger(__name__)
@@ -31,20 +29,10 @@ class FragmentPremium:
'x-requested-with': 'XMLHttpRequest'
}
self.transaction_processor = TransactionProcessor(self.config, self._clean_decode)
self.transaction_processor = TransactionProcessor(self.config, clean_decode)
self.wallet_linker = WalletLinker(self.config, self.headers, self.transaction_processor)
self.api_client = ApiClient(self.config, self.headers, self.wallet_linker)
@staticmethod
def _clean_decode(s):
b = base64.b64decode(re.sub(r'[^A-Za-z0-9+/=]', '', s.strip()) + "=" * (-len(s) % 4))
t = next(
(b[i:].decode('utf-8', 'ignore') for i in range(20) if
b[i:].decode('utf-8', 'ignore').startswith("Telegram Premium")),
b.decode('utf-8', 'ignore')
)
return ''.join(c for c in t if c in string.printable or c in '\n\r\t ').strip()
async def _get_account_info(self):
client = TonapiClient(api_key=self.config['api_key'], is_testnet=False)
wallet, pub_key, _, _ = WalletV5R1.from_mnemonic(client=client, mnemonic=self.config['seed'])
@@ -67,7 +55,12 @@ class FragmentPremium:
search_data = {"query": username, "months": months, "method": "searchPremiumGiftRecipient"}
search_resp = await client.post(f"https://fragment.com/api?hash={self.config['hash']}",
headers=self.headers, data=search_data)
search_result = search_resp.json()
try:
search_result = search_resp.json()
except Exception as e:
logger.error(f"Failed to parse search response: {e}")
return {"success": False, "error": f"Invalid response from Fragment API: {str(e)}"}
recipient = search_result.get("found", {}).get("recipient")
if not recipient:
@@ -80,7 +73,14 @@ class FragmentPremium:
init_data = {"recipient": recipient, "months": months, "method": "initGiftPremiumRequest"}
init_resp = await client.post(f"https://fragment.com/api?hash={self.config['hash']}",
headers=self.headers, data=init_data)
init_result = init_resp.json()
try:
init_result = init_resp.json()
except Exception as e:
logger.error(f"Failed to parse init response: {e}")
logger.error(f"Response status: {init_resp.status_code}")
logger.error(f"Response content: {init_resp.content[:200]}")
return {"success": False, "error": f"Invalid response from Fragment API: {str(e)}"}
req_id = init_result.get("req_id")
if not req_id:
+16 -13
View File
@@ -1,6 +1,5 @@
import base64
import logging
import re
import time
import httpx
@@ -8,7 +7,7 @@ from tonutils.client import TonapiClient
from tonutils.wallet import WalletV5R1
from app.core.config import Config
from app.utils import TransactionProcessor, WalletLinker, ApiClient
from app.utils import TransactionProcessor, WalletLinker, ApiClient, clean_decode
logger = logging.getLogger(__name__)
@@ -30,18 +29,10 @@ class FragmentStars:
'x-requested-with': 'XMLHttpRequest'
}
self.transaction_processor = TransactionProcessor(self.config, self._clean_decode)
self.transaction_processor = TransactionProcessor(self.config, clean_decode)
self.wallet_linker = WalletLinker(self.config, self.headers, self.transaction_processor)
self.api_client = ApiClient(self.config, self.headers, self.wallet_linker)
@staticmethod
def _clean_decode(s):
s = re.sub(r'[^A-Za-z0-9+/=]', '', s.strip())
b = base64.b64decode(s + "=" * (-len(s) % 4))
t = b.decode('utf-8', 'ignore')
m = re.search(r'(\d+\s+Telegram\s+Stars.*?Ref#[A-Za-z0-9]+)', t, re.S)
return m.group(1).strip() if m else t.strip()
async def _get_account_info(self):
client = TonapiClient(api_key=self.config['api_key'], is_testnet=False)
wallet, pub_key, _, _ = WalletV5R1.from_mnemonic(client=client, mnemonic=self.config['seed'])
@@ -64,7 +55,12 @@ class FragmentStars:
search_data = {"query": username, "quantity": "", "method": "searchStarsRecipient"}
search_resp = await client.post(f"https://fragment.com/api?hash={self.config['hash']}",
headers=self.headers, data=search_data)
search_result = search_resp.json()
try:
search_result = search_resp.json()
except Exception as e:
logger.error(f"Failed to parse search response: {e}")
return {"success": False, "error": f"Invalid response from Fragment API: {str(e)}"}
recipient = search_result.get("found", {}).get("recipient")
if not recipient:
@@ -73,7 +69,14 @@ class FragmentStars:
init_data = {"recipient": recipient, "quantity": amount, "method": "initBuyStarsRequest"}
init_resp = await client.post(f"https://fragment.com/api?hash={self.config['hash']}",
headers=self.headers, data=init_data)
init_result = init_resp.json()
try:
init_result = init_resp.json()
except Exception as e:
logger.error(f"Failed to parse init response: {e}")
logger.error(f"Response status: {init_resp.status_code}")
logger.error(f"Response content: {init_resp.content[:200]}")
return {"success": False, "error": f"Invalid response from Fragment API: {str(e)}"}
req_id = init_result.get("req_id")
if not req_id:
+16 -12
View File
@@ -1,6 +1,5 @@
import base64
import logging
import re
import time
import httpx
@@ -8,7 +7,7 @@ from tonutils.client import TonapiClient
from tonutils.wallet import WalletV5R1
from app.core.config import Config
from app.utils import TransactionProcessor, WalletLinker, ApiClient
from app.utils import TransactionProcessor, WalletLinker, ApiClient, clean_decode
logger = logging.getLogger(__name__)
@@ -30,17 +29,10 @@ class FragmentTon:
'x-requested-with': 'XMLHttpRequest'
}
self.transaction_processor = TransactionProcessor(self.config, self._clean_decode)
self.transaction_processor = TransactionProcessor(self.config, clean_decode)
self.wallet_linker = WalletLinker(self.config, self.headers, self.transaction_processor)
self.api_client = ApiClient(self.config, self.headers, self.wallet_linker)
@staticmethod
def _clean_decode(s):
t = base64.b64decode(re.sub(r'[^A-Za-z0-9+/=]', '', s.strip()) + "=" * (-len(s) % 4)).decode('utf-8',
errors='ignore')
t = ''.join(c for c in t if c.isprintable() or c.isspace())
return t.lstrip("r0N").strip()
async def _get_account_info(self):
client = TonapiClient(api_key=self.config['api_key'], is_testnet=False)
wallet, pub_key, _, _ = WalletV5R1.from_mnemonic(client=client, mnemonic=self.config['seed'])
@@ -67,7 +59,12 @@ class FragmentTon:
search_data = {"query": username, "method": "searchAdsTopupRecipient"}
search_resp = await client.post(f"https://fragment.com/api?hash={self.config['hash']}",
headers=self.headers, data=search_data)
search_result = search_resp.json()
try:
search_result = search_resp.json()
except Exception as e:
logger.error(f"Failed to parse search response: {e}")
return {"success": False, "error": f"Invalid response from Fragment API: {str(e)}"}
recipient = search_result.get("found", {}).get("recipient")
if not recipient:
@@ -76,7 +73,14 @@ class FragmentTon:
init_data = {"recipient": recipient, "amount": amount, "method": "initAdsTopupRequest"}
init_resp = await client.post(f"https://fragment.com/api?hash={self.config['hash']}",
headers=self.headers, data=init_data)
init_result = init_resp.json()
try:
init_result = init_resp.json()
except Exception as e:
logger.error(f"Failed to parse init response: {e}")
logger.error(f"Response status: {init_resp.status_code}")
logger.error(f"Response content: {init_resp.content[:200]}")
return {"success": False, "error": f"Invalid response from Fragment API: {str(e)}"}
req_id = init_result.get("req_id")
if not req_id: