Fix an issue with campaigns having an incorrect allowed channels list
This commit is contained in:
1 parent
d8958d746c
commit
fdd0172abf
1 file changed
+35
-24
@@ -6,6 +6,7 @@ import asyncio
|
|||||||
import logging
|
import logging
|
||||||
from math import ceil
|
from math import ceil
|
||||||
from time import time
|
from time import time
|
||||||
|
from itertools import chain
|
||||||
from functools import partial
|
from functools import partial
|
||||||
# from base64 import urlsafe_b64decode
|
# from base64 import urlsafe_b64decode
|
||||||
from collections import abc, OrderedDict
|
from collections import abc, OrderedDict
|
||||||
@@ -1059,23 +1060,35 @@ class Twitch:
|
|||||||
raise MinerException(f"GQL error: {response_json['errors']}")
|
raise MinerException(f"GQL error: {response_json['errors']}")
|
||||||
return response_json
|
return response_json
|
||||||
|
|
||||||
async def fetch_campaign(
|
def _merge_data(self, primary_data: JsonType, secondary_data: JsonType) -> JsonType:
|
||||||
self,
|
merged = {}
|
||||||
campaign_id: str,
|
for key in set(chain(primary_data.keys(), secondary_data.keys())):
|
||||||
available_data: JsonType,
|
in_primary = key in primary_data
|
||||||
claimed_benefits: dict[str, datetime],
|
in_secondary = key in secondary_data
|
||||||
) -> DropsCampaign:
|
if in_primary and in_secondary:
|
||||||
|
vp = primary_data[key]
|
||||||
|
vs = secondary_data[key]
|
||||||
|
if not isinstance(vp, type(vs)) or not isinstance(vs, type(vp)):
|
||||||
|
raise MinerException("Inconsistent merge data")
|
||||||
|
if isinstance(vp, dict): # both are dicts
|
||||||
|
merged[key] = self._merge_data(vp, vs)
|
||||||
|
else:
|
||||||
|
# use primary value
|
||||||
|
merged[key] = vp
|
||||||
|
elif in_primary:
|
||||||
|
merged[key] = primary_data[key]
|
||||||
|
else: # in campaigns only
|
||||||
|
merged[key] = secondary_data[key]
|
||||||
|
return merged
|
||||||
|
|
||||||
|
async def fetch_campaign(self, campaign_id: str, available_data: JsonType) -> JsonType:
|
||||||
auth_state = await self.get_auth()
|
auth_state = await self.get_auth()
|
||||||
response = await self.gql_request(
|
response = await self.gql_request(
|
||||||
GQL_OPERATIONS["CampaignDetails"].with_variables(
|
GQL_OPERATIONS["CampaignDetails"].with_variables(
|
||||||
{"channelLogin": str(auth_state.user_id), "dropID": campaign_id}
|
{"channelLogin": str(auth_state.user_id), "dropID": campaign_id}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
campaign_data: JsonType = response["data"]["user"]["dropCampaign"]
|
return self._merge_data(available_data, response["data"]["user"]["dropCampaign"])
|
||||||
# NOTE: we use available_data to add a couple of fields missing from the existing details,
|
|
||||||
# most notably: game boxart
|
|
||||||
campaign_data["game"]["boxArtURL"] = available_data["game"]["boxArtURL"]
|
|
||||||
return DropsCampaign(self, campaign_data, claimed_benefits)
|
|
||||||
|
|
||||||
async def fetch_inventory(self) -> None:
|
async def fetch_inventory(self) -> None:
|
||||||
status_update = self.gui.status.update
|
status_update = self.gui.status.update
|
||||||
@@ -1088,22 +1101,15 @@ class Twitch:
|
|||||||
claimed_benefits: dict[str, datetime] = {
|
claimed_benefits: dict[str, datetime] = {
|
||||||
b["id"]: timestamp(b["lastAwardedAt"]) for b in inventory["gameEventDrops"]
|
b["id"]: timestamp(b["lastAwardedAt"]) for b in inventory["gameEventDrops"]
|
||||||
}
|
}
|
||||||
campaigns: list[DropsCampaign] = [
|
inventory_data: dict[str, JsonType] = {c["id"]: c for c in ongoing_campaigns}
|
||||||
DropsCampaign(self, campaign_data, claimed_benefits)
|
|
||||||
for campaign_data in ongoing_campaigns
|
|
||||||
]
|
|
||||||
# fetch all available campaigns data
|
# fetch all available campaigns data
|
||||||
response = await self.gql_request(GQL_OPERATIONS["Campaigns"])
|
response = await self.gql_request(GQL_OPERATIONS["Campaigns"])
|
||||||
available_list: list[JsonType] = response["data"]["currentUser"]["dropCampaigns"] or []
|
available_list: list[JsonType] = response["data"]["currentUser"]["dropCampaigns"] or []
|
||||||
applicable_statuses = ("ACTIVE", "UPCOMING")
|
applicable_statuses = ("ACTIVE", "UPCOMING")
|
||||||
existing_campaigns: set[str] = set(c.id for c in campaigns)
|
|
||||||
available_campaigns: dict[str, JsonType] = {
|
available_campaigns: dict[str, JsonType] = {
|
||||||
c["id"]: c
|
c["id"]: c
|
||||||
for c in available_list
|
for c in available_list
|
||||||
if (
|
if c["status"] in applicable_statuses # that are currently not expired
|
||||||
c["status"] in applicable_statuses # that are currently ACTIVE
|
|
||||||
and c["id"] not in existing_campaigns # and they aren't in the inventory already
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
# add campaigns that remained, that can be earned but are not in-progress yet
|
# add campaigns that remained, that can be earned but are not in-progress yet
|
||||||
status_update(
|
status_update(
|
||||||
@@ -1111,23 +1117,28 @@ class Twitch:
|
|||||||
counter=f"(0/{len(available_campaigns)})"
|
counter=f"(0/{len(available_campaigns)})"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
fetched_campaigns: list[DropsCampaign] = []
|
fetched_campaigns: dict[str, JsonType] = {}
|
||||||
for i, coro in enumerate(
|
for i, coro in enumerate(
|
||||||
# specifically use an intermediate list per a Python bug
|
# specifically use an intermediate list per a Python bug
|
||||||
# https://github.com/python/cpython/issues/88342
|
# https://github.com/python/cpython/issues/88342
|
||||||
asyncio.as_completed([
|
asyncio.as_completed([
|
||||||
self.fetch_campaign(campaign_id, available_data, claimed_benefits)
|
self.fetch_campaign(campaign_id, available_data)
|
||||||
for campaign_id, available_data in available_campaigns.items()
|
for campaign_id, available_data in available_campaigns.items()
|
||||||
]),
|
]),
|
||||||
start=1,
|
start=1,
|
||||||
):
|
):
|
||||||
fetched_campaigns.append(await coro)
|
|
||||||
status_update(
|
status_update(
|
||||||
_("gui", "status", "fetching_campaigns").format(
|
_("gui", "status", "fetching_campaigns").format(
|
||||||
counter=f"({i}/{len(available_campaigns)})"
|
counter=f"({i}/{len(available_campaigns)})"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
campaigns.extend(fetched_campaigns)
|
campaign_data = await coro
|
||||||
|
fetched_campaigns[campaign_data["id"]] = campaign_data
|
||||||
|
merged_campaigns: dict[str, JsonType] = self._merge_data(inventory_data, fetched_campaigns)
|
||||||
|
campaigns: list[DropsCampaign] = [
|
||||||
|
DropsCampaign(self, campaign_data, claimed_benefits)
|
||||||
|
for campaign_data in merged_campaigns.values()
|
||||||
|
]
|
||||||
campaigns.sort(key=lambda c: c.active, reverse=True)
|
campaigns.sort(key=lambda c: c.active, reverse=True)
|
||||||
campaigns.sort(key=lambda c: c.upcoming and c.starts_at or c.ends_at)
|
campaigns.sort(key=lambda c: c.upcoming and c.starts_at or c.ends_at)
|
||||||
campaigns.sort(key=lambda c: c.linked, reverse=True)
|
campaigns.sort(key=lambda c: c.linked, reverse=True)
|
||||||
|
|||||||
Reference in new issue
Block a user