Bhoonidhi SDK — cart¶
Stage scenes into the portal's carts, list what's staged, and remove
items. Every method matches a bhd cart command.
Runs live and needs a login. add and rm change your real cart, so
they're left commented — uncomment to run them. list is read-only.
1. Log in¶
import getpass
from bhoonidhi_downloader.sdk import BhoonidhiClient, BhoonidhiError
def get_otp(message: str) -> str:
print(message)
return input("Enter the 6-digit OTP: ")
client = BhoonidhiClient()
# otp_prompt is only called if the account needs a mailed OTP; a
# password-only account logs in without it being invoked.
client.login(
input("Bhoonidhi username: "),
getpass.getpass("Bhoonidhi password: "),
otp_prompt=get_otp,
)
print("authenticated:", client.is_authenticated)
2. List the cart¶
client.cart.list() matches bhd cart list. Merges all three carts (direct, on-order, priced) into one list. With no dates it shows items added today.
# items = client.cart.list()
from datetime import datetime
items = client.cart.list(since=datetime(2026,8,10), filter_by=["priced", "onOrder"])
print("items in today's cart:", len(items))
for it in items[:8]:
print(" ", it.get("ID"), "|", it.get("_cart"), "|", it.get("STATUS"))
items in today's cart: 24 R2A_AWIF_-_03-JUL-2026_77_49_A_JDP_49660_03-JUL-2026_PLD_49660_1_000_432_JDP_PLD _1_49660_JDP_PLD _1_49660_1 | CartKind.ORDER | A R2A_AWIF_-_03-JUL-2026_77_44_C_JDP_49660_03-JUL-2026_PLD_49660_1_000_432_JDP_PLD _1_49660_JDP_PLD _1_49660_1 | CartKind.ORDER | A R2A_AWIF_-_08-JUL-2026_78_43_C_JDP_49731_08-JUL-2026_PLD_49731_1_000_432_JDP_PLD _1_49731_JDP_PLD _1_49731_1 | CartKind.ORDER | A R2A_AWIF_-_13-JUL-2026_79_46_A_JDP_49802_13-JUL-2026_PLD_49802_1_000_432_JDP_PLD _1_49802_JDP_PLD _1_49802_1 | CartKind.ORDER | A R2A_AWIF_-_13-JUL-2026_79_46_C_JDP_49802_13-JUL-2026_PLD_49802_1_000_432_JDP_PLD _1_49802_JDP_PLD _1_49802_1 | CartKind.ORDER | A R2A_AWIF_-_08-JUL-2026_78_48_A_JDP_49731_08-JUL-2026_PLD_49731_1_000_432_JDP_PLD _1_49731_JDP_PLD _1_49731_1 | CartKind.ORDER | A R2A_AWIF_-_10-AUG-2026_99_53_A_SAN_50199_10-AUG-2026_PLD_50199_1_000_432_SAN_PLD _1_50199_SAN_PLD _1_50199_1 | CartKind.ORDER | A RAW12JUL2026049787009800051PSANSTLC00GTDA | CartKind.ORDER | A
3. Widen the date window¶
Cart items are filed by add-date. Use last, or since/until, to look back further.
recent = client.cart.list(last="2 weeks")
print("items added in the last 2 weeks:", len(recent))
items added in the last 2 weeks: 210
4. Filter by state¶
filter_by keeps only rows in the given states: ready, archived, onorder, priced.
for state in ("ready", "archived", "onorder", "priced"):
print(f"{state:9s}: {len(client.cart.list(last='1 month', filter_by=[state]))}")
ready : 96 archived : 7 onorder : 37 priced : 70
5. Add a query's scenes to the cart¶
client.cart.add(slug, select=...) matches bhd cart add. Returns (added, failed, srt). select is a list of indices/IDs — e.g. [1, 2] — or omit it for the whole query. Uncomment to run.
slug = client.query.list()[0].slug # some saved query
added, failed, srt = client.cart.add(slug, select=[1, 2])
print("added: ", [(s.get("ID"), k) for s, k in added])
print("failed:", [(s.get("ID"), reason) for s, reason in failed])
print("search id:", srt)
added: [('RAW12JUL2026049787009800051PSANSTLC00GTDA', <CartKind.DIRECT: 'direct'>), ('RAW12JUL2026049787009800051PSANSTLCSRHTDA', <CartKind.DIRECT: 'direct'>)]
failed: []
search id: 20260810_LDP015268
6. Remove from the cart¶
client.cart.rm(...) matches bhd cart rm. Address rows two ways: pass slug to index a query's scenes, or omit it and select indexes the merged cart (same numbers as list). Uncomment to run.
# by cart row number (matches what list() shows under the same filters):
removed, failed = client.cart.rm(select=[1])
print("removed:", removed)
print("failed: ", failed)
# or by a saved query's scenes:
# removed, failed = client.cart.rm(slug, select=[1, 2])
removed: [('RAW03JUL2026049660007700044PSANSTLC00GTDC', <CartKind.DIRECT: 'direct'>)]
failed: []
7. Errors¶
add to an unknown query raises; a bad filter raises.
from bhoonidhi_downloader.exceptions import BhoonidhiNotFoundError
try:
client.cart.add("no-such-query")
except BhoonidhiNotFoundError as e:
print("add(unknown) ->", type(e).__name__, "-", e)
try:
client.cart.list(filter_by=["nonsense"])
except ValueError as e:
print("bad filter ->", e)
add(unknown) -> BhoonidhiNotFoundError - no-such-query bad filter -> Unknown filter 'nonsense'. Valid values: archived, onorder, priced, ready.