First release
This commit is contained in:
commit
fac2788e4b
12 files changed
+1164
No files matched your search
+128
@@ -0,0 +1,128 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Any, Optional, List, Dict, TYPE_CHECKING
|
||||
|
||||
from constants import GQL_OPERATIONS
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from twitch import Twitch
|
||||
|
||||
|
||||
async def claim_drop(twitch: Twitch, claim_id: str) -> bool:
|
||||
op = GQL_OPERATIONS["ClaimDrop"].with_variables(
|
||||
{"input": {"dropInstanceID": claim_id}}
|
||||
)
|
||||
response = await twitch.gql_request(op)
|
||||
data = response["data"]
|
||||
if "errors" in data and data["errors"]:
|
||||
return False
|
||||
elif "claimDropRewards" in data:
|
||||
if not data["claimDropRewards"]:
|
||||
return False
|
||||
elif (
|
||||
data["claimDropRewards"]["status"]
|
||||
in ["ELIGIBLE_FOR_ALL", "DROP_INSTANCE_ALREADY_CLAIMED"]
|
||||
):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class Game:
|
||||
def __init__(self, data: Dict[str, Any]):
|
||||
self.id: int = int(data["id"])
|
||||
self.name: str = data["name"]
|
||||
|
||||
def __eq__(self, other: object):
|
||||
if isinstance(other, self.__class__):
|
||||
return self.id == other.id
|
||||
return NotImplemented
|
||||
|
||||
def __hash__(self) -> int:
|
||||
return self.id
|
||||
|
||||
|
||||
class BaseDrop:
|
||||
def __init__(self, campaign: DropsCampaign, data: Dict[str, Any]):
|
||||
self._twitch: Twitch = campaign._twitch
|
||||
self.id = data["id"]
|
||||
self.name: str = data["name"]
|
||||
self.campaign: DropsCampaign = campaign
|
||||
self.rewards: List[str] = [b["benefit"]["name"] for b in data["benefitEdges"]]
|
||||
self.starts_at: datetime = datetime.strptime(data["startAt"], "%Y-%m-%dT%H:%M:%SZ")
|
||||
self.ends_at: datetime = datetime.strptime(data["endAt"], "%Y-%m-%dT%H:%M:%SZ")
|
||||
# If claim_id is not None, we can use it to claim the drop
|
||||
self.claim_id: Optional[str] = data["self"]["dropInstanceID"]
|
||||
self.is_claimed: bool = data["self"]["isClaimed"]
|
||||
self._preconditions: bool = data["self"]["hasPreconditionsMet"]
|
||||
|
||||
@property
|
||||
def can_earn(self) -> bool:
|
||||
return (
|
||||
self._preconditions # preconditions are met
|
||||
and self.campaign.active # campaign is active
|
||||
and not self.is_claimed # drop isn't already claimed
|
||||
)
|
||||
|
||||
@property
|
||||
def can_claim(self) -> bool:
|
||||
return self.claim_id is not None and not self.is_claimed
|
||||
|
||||
async def claim(self) -> bool:
|
||||
"""
|
||||
Returns True if the claim succeeded, False otherwise.
|
||||
"""
|
||||
if not self.can_claim:
|
||||
return False
|
||||
assert self.claim_id is not None
|
||||
self.is_claimed = await claim_drop(self._twitch, self.claim_id)
|
||||
return self.is_claimed
|
||||
|
||||
|
||||
class TimedDrop(BaseDrop):
|
||||
def __init__(self, campaign: DropsCampaign, data: Dict[str, Any]):
|
||||
super().__init__(campaign, data)
|
||||
self.current_minutes: int = data["self"]["currentMinutesWatched"]
|
||||
self.required_minutes: int = data["requiredMinutesWatched"]
|
||||
if self.is_claimed:
|
||||
# correct minutes for claimed drops
|
||||
self.current_minutes = self.required_minutes
|
||||
|
||||
@property
|
||||
def remaining_minutes(self):
|
||||
return self.required_minutes - self.current_minutes
|
||||
|
||||
@property
|
||||
def progress(self):
|
||||
return self.current_minutes / self.required_minutes
|
||||
|
||||
def update(self, message: Dict[str, Any]):
|
||||
# {"type": "drop-progress", data: {"current_progress_min": 3, "required_progress_min": 10}}
|
||||
# {"type": "drop-claim", data: {"drop_instance_id": ...}}
|
||||
msg_type = message["type"]
|
||||
if msg_type == "drop-progress":
|
||||
self.current_minutes = message["data"]["current_progress_min"]
|
||||
self.required_minutes = message["data"]["required_progress_min"]
|
||||
elif msg_type == "drop-claim":
|
||||
self.claim_id = message["data"]["drop_instance_id"]
|
||||
|
||||
|
||||
class DropsCampaign:
|
||||
def __init__(self, twitch: Twitch, data: Dict[str, Any]):
|
||||
self._twitch: Twitch = twitch
|
||||
self.id: str = data["id"]
|
||||
self.name: str = data["name"]
|
||||
self.game: Game = Game(data["game"])
|
||||
self.starts_at: datetime = datetime.strptime(data["startAt"], "%Y-%m-%dT%H:%M:%SZ")
|
||||
self.ends_at: datetime = datetime.strptime(data["endAt"], "%Y-%m-%dT%H:%M:%SZ")
|
||||
self.status: str = data["status"]
|
||||
self.timed_drops: Dict[str, TimedDrop] = {
|
||||
d["id"]: TimedDrop(self, d) for d in data["timeBasedDrops"]
|
||||
}
|
||||
|
||||
@property
|
||||
def active(self):
|
||||
return self.status == "ACTIVE"
|
||||
|
||||
def get_drop(self, drop_id: str) -> Optional[TimedDrop]:
|
||||
return self.timed_drops.get(drop_id)
|
||||
Reference in new issue
Block a user