99import calendar
1010import typing as t
1111from functools import partial
12- from distutils .version import LooseVersion # pylint: disable=no-name-in-module,import-error
12+ from contextlib import suppress
13+ from distutils .version import LooseVersion
1314
1415sys .path .insert (0 , str (pathlib .PurePath (__file__ ).parent / 'modules' ))
1516
2223
2324from consts import IS_WINDOWS , TROVE_SUBSCRIPTION_NAME
2425from settings import Settings
25- from webservice import AuthorizedHumbleAPI
26+ from webservice import AuthorizedHumbleAPI , WebpackParseError
2627from model .game import TroveGame , Key , Subproduct , HumbleGame , ChoiceGame
27- from model .types import HP , Tier
28+ from model .types import HP
2829from humbledownloader import HumbleDownloadResolver
2930from library import LibraryResolver
3031from local import AppFinder
3132from privacy import SensitiveFilter
33+ from active_month_resolver import (
34+ ActiveMonthInfoByUser ,
35+ ActiveMonthResolver ,
36+ )
3237from utils .decorators import double_click_effect
3338from gui .options import OPTIONS_MODE
3439import guirunner as gui
@@ -112,7 +117,7 @@ def handshake_complete(self):
112117
113118 async def _get_user_name (self ) -> str :
114119 try :
115- marketing_data = await self ._api .get_choice_marketing_data ()
120+ marketing_data = await self ._api .get_main_page_webpack_data ()
116121 return marketing_data ['userOptions' ]['email' ].split ('@' )[0 ]
117122 except (BackendError , KeyError , UnknownBackendResponse ) as e :
118123 logger .error (repr (e ))
@@ -182,56 +187,53 @@ def _normalize_subscription_name(machine_name: str):
182187 'november' : '11' ,
183188 'december' : '12'
184189 }
185- month , year , type_ = machine_name .split ('_' )
190+ try :
191+ month , year , type_ = machine_name .split ('_' )
192+ except Exception :
193+ assert False , f"is { machine_name } "
186194 return f'Humble { type_ .title ()} { year } -{ month_map [month ]} '
187195
188196 @staticmethod
189197 def _choice_name_to_slug (subscription_name : str ):
190- _ , type_ , year_month = subscription_name .split (' ' )
198+ _ , _ , year_month = subscription_name .split (' ' )
191199 year , month = year_month .split ('-' )
192200 return f'{ calendar .month_name [int (month )]} -{ year } ' .lower ()
193201
194- async def _get_active_month_machine_name (self ) -> str :
195- marketing_data = await self ._api .get_choice_marketing_data ()
196- return marketing_data ['activeContentMachineName' ]
197-
198202 async def get_subscriptions (self ):
199203 subscriptions : t .List [Subscription ] = []
200- current_plan = await self ._api .get_subscription_plan ()
201- active_content_unlocked = False
204+ subscription_state = await self ._api .get_user_subscription_state ()
205+ # perks are Trove and store discount; paused month makes perks "inactive"
206+ has_active_subscription = subscription_state .get ("perksStatus" ) == "active"
207+ owns_active_content = subscription_state .get ("monthlyOwnsActiveContent" )
208+
209+ subscriptions .append (Subscription (
210+ subscription_name = TROVE_SUBSCRIPTION_NAME ,
211+ owned = has_active_subscription
212+ ))
202213
203214 async for product in self ._api .get_subscription_products_with_gamekeys ():
204215 if 'contentChoiceData' not in product :
205216 break # all Humble Choice months already yielded
206-
207- is_active = product .get ('isActiveContent' , False )
217+ is_product_unlocked = 'gamekey' in product
208218 subscriptions .append (Subscription (
209219 self ._normalize_subscription_name (product ['productMachineName' ]),
210- owned = 'gamekey' in product
211- ))
212- active_content_unlocked |= is_active # assuming there is only one "active" month at a time
213-
214- if not active_content_unlocked :
215- '''
216- - for not subscribers as potential discovery of current choice games
217- - for subscribers who has not used "Early Unlock" yet:
218- https://support.humblebundle.com/hc/en-us/articles/217300487-Humble-Choice-Early-Unlock-Games
219- '''
220- active_month_machine_name = await self ._get_active_month_machine_name ()
221- subscriptions .append (Subscription (
222- self ._normalize_subscription_name (active_month_machine_name ),
223- owned = current_plan is not None and current_plan .tier != Tier .LITE , # TODO: last month of not payed subs are still returned
224- end_time = None # #117: get_last_friday.timestamp() if user_plan not in [None, Lite] else None
220+ owned = is_product_unlocked
225221 ))
226222
227- subscriptions .append (Subscription (
228- subscription_name = TROVE_SUBSCRIPTION_NAME ,
229- owned = current_plan is not None
230- ))
223+ if not owns_active_content :
224+ active_month_resolver = ActiveMonthResolver (has_active_subscription )
225+ active_month_info : ActiveMonthInfoByUser = await active_month_resolver .resolve (self ._api )
226+
227+ if active_month_info .machine_name :
228+ subscriptions .append (Subscription (
229+ self ._normalize_subscription_name (active_month_info .machine_name ),
230+ owned = active_month_info .is_or_will_be_owned ,
231+ end_time = None # #117: get_last_friday.timestamp() if user_plan not in [None, Lite] else None
232+ ))
231233
232234 return subscriptions
233235
234- async def _get_trove_games (self ):
236+ async def _get_trove_games (self ) -> t . AsyncGenerator [ t . List [ SubscriptionGame ], None ] :
235237 def parse_and_cache (troves ):
236238 games : t .List [SubscriptionGame ] = []
237239 for trove in troves :
@@ -243,12 +245,13 @@ def parse_and_cache(troves):
243245 logging .warning (f"Error while parsing trove { repr (e )} : { trove } " , extra = {'data' : trove })
244246 return games
245247
246- newly_added = (await self ._api .get_montly_trove_data ()).get ('newlyAdded' , [])
247- if newly_added :
248- yield parse_and_cache (newly_added )
248+ with suppress (WebpackParseError ):
249+ newly_added = (await self ._api .get_montly_trove_data ()).get ('newlyAdded' , [])
250+ if newly_added :
251+ yield parse_and_cache (newly_added )
249252 async for troves in self ._api .get_trove_details ():
250253 yield parse_and_cache (troves )
251-
254+
252255 async def get_subscription_games (self , subscription_name , context ):
253256 if subscription_name == TROVE_SUBSCRIPTION_NAME :
254257 async for troves in self ._get_trove_games ():
0 commit comments