python-xbox 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- python_xbox-0.1.0.dist-info/METADATA +217 -0
- python_xbox-0.1.0.dist-info/RECORD +64 -0
- python_xbox-0.1.0.dist-info/WHEEL +4 -0
- python_xbox-0.1.0.dist-info/entry_points.txt +6 -0
- python_xbox-0.1.0.dist-info/licenses/LICENSE +20 -0
- pythonxbox/__init__.py +4 -0
- pythonxbox/api/__init__.py +0 -0
- pythonxbox/api/client.py +166 -0
- pythonxbox/api/language.py +76 -0
- pythonxbox/api/provider/__init__.py +0 -0
- pythonxbox/api/provider/account/__init__.py +73 -0
- pythonxbox/api/provider/account/models.py +11 -0
- pythonxbox/api/provider/achievements/__init__.py +164 -0
- pythonxbox/api/provider/achievements/models.py +133 -0
- pythonxbox/api/provider/baseprovider.py +22 -0
- pythonxbox/api/provider/catalog/__init__.py +86 -0
- pythonxbox/api/provider/catalog/const.py +15 -0
- pythonxbox/api/provider/catalog/models.py +428 -0
- pythonxbox/api/provider/cqs/__init__.py +85 -0
- pythonxbox/api/provider/cqs/models.py +59 -0
- pythonxbox/api/provider/gameclips/__init__.py +167 -0
- pythonxbox/api/provider/gameclips/models.py +58 -0
- pythonxbox/api/provider/lists/__init__.py +71 -0
- pythonxbox/api/provider/lists/models.py +33 -0
- pythonxbox/api/provider/mediahub/__init__.py +64 -0
- pythonxbox/api/provider/mediahub/models.py +82 -0
- pythonxbox/api/provider/message/__init__.py +135 -0
- pythonxbox/api/provider/message/models.py +96 -0
- pythonxbox/api/provider/people/__init__.py +193 -0
- pythonxbox/api/provider/people/models.py +252 -0
- pythonxbox/api/provider/presence/__init__.py +110 -0
- pythonxbox/api/provider/presence/models.py +53 -0
- pythonxbox/api/provider/profile/__init__.py +140 -0
- pythonxbox/api/provider/profile/models.py +47 -0
- pythonxbox/api/provider/ratelimitedprovider.py +79 -0
- pythonxbox/api/provider/screenshots/__init__.py +167 -0
- pythonxbox/api/provider/screenshots/models.py +56 -0
- pythonxbox/api/provider/smartglass/__init__.py +402 -0
- pythonxbox/api/provider/smartglass/models.py +186 -0
- pythonxbox/api/provider/titlehub/__init__.py +143 -0
- pythonxbox/api/provider/titlehub/models.py +106 -0
- pythonxbox/api/provider/usersearch/__init__.py +29 -0
- pythonxbox/api/provider/usersearch/models.py +17 -0
- pythonxbox/api/provider/userstats/__init__.py +164 -0
- pythonxbox/api/provider/userstats/models.py +44 -0
- pythonxbox/authentication/__init__.py +0 -0
- pythonxbox/authentication/manager.py +161 -0
- pythonxbox/authentication/models.py +162 -0
- pythonxbox/authentication/xal.py +348 -0
- pythonxbox/common/__init__.py +0 -0
- pythonxbox/common/exceptions.py +59 -0
- pythonxbox/common/filetimes.py +81 -0
- pythonxbox/common/models.py +34 -0
- pythonxbox/common/ratelimits/__init__.py +268 -0
- pythonxbox/common/ratelimits/models.py +23 -0
- pythonxbox/common/request_signer.py +190 -0
- pythonxbox/common/signed_session.py +60 -0
- pythonxbox/py.typed +0 -0
- pythonxbox/scripts/__init__.py +15 -0
- pythonxbox/scripts/authenticate.py +159 -0
- pythonxbox/scripts/change_gamertag.py +111 -0
- pythonxbox/scripts/friends.py +80 -0
- pythonxbox/scripts/search.py +43 -0
- pythonxbox/scripts/xal.py +113 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Achievements
|
|
3
|
+
|
|
4
|
+
Get Xbox 360 and Xbox One Achievement data
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from pythonxbox.api.provider.achievements.models import (
|
|
8
|
+
Achievement360ProgressResponse,
|
|
9
|
+
Achievement360Response,
|
|
10
|
+
AchievementResponse,
|
|
11
|
+
RecentProgressResponse,
|
|
12
|
+
)
|
|
13
|
+
from pythonxbox.api.provider.ratelimitedprovider import RateLimitedProvider
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class AchievementsProvider(RateLimitedProvider):
|
|
17
|
+
ACHIEVEMENTS_URL = "https://achievements.xboxlive.com"
|
|
18
|
+
HEADERS_GAME_360_PROGRESS = {"x-xbl-contract-version": "1"}
|
|
19
|
+
HEADERS_GAME_PROGRESS = {"x-xbl-contract-version": "2"}
|
|
20
|
+
|
|
21
|
+
RATE_LIMITS = {"burst": 100, "sustain": 300}
|
|
22
|
+
|
|
23
|
+
async def get_achievements_detail_item(
|
|
24
|
+
self, xuid: str, service_config_id: str, achievement_id: str, **kwargs
|
|
25
|
+
) -> AchievementResponse:
|
|
26
|
+
"""
|
|
27
|
+
Get achievement detail for specific item
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
xuid (str): Xbox User Id
|
|
31
|
+
service_config_id (str): Service Config Id
|
|
32
|
+
achievement_id (str): Achievement Id
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
:class:`AchievementResponse`: Achievement Response
|
|
36
|
+
"""
|
|
37
|
+
url = f"{self.ACHIEVEMENTS_URL}/users/xuid({xuid})/achievements/{service_config_id}/{achievement_id}"
|
|
38
|
+
resp = await self.client.session.get(
|
|
39
|
+
url,
|
|
40
|
+
headers=self.HEADERS_GAME_PROGRESS,
|
|
41
|
+
rate_limits=self.rate_limit_read,
|
|
42
|
+
**kwargs,
|
|
43
|
+
)
|
|
44
|
+
resp.raise_for_status()
|
|
45
|
+
return AchievementResponse(**resp.json())
|
|
46
|
+
|
|
47
|
+
async def get_achievements_xbox360_all(
|
|
48
|
+
self, xuid: str, title_id: str, **kwargs
|
|
49
|
+
) -> Achievement360Response:
|
|
50
|
+
"""
|
|
51
|
+
Get all achievements for specific X360 title Id
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
xuid (str): Xbox User Id
|
|
55
|
+
title_id (str): Xbox 360 Title Id
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
:class:`Achievement360Response`: Achievement 360 Response
|
|
59
|
+
"""
|
|
60
|
+
url = f"{self.ACHIEVEMENTS_URL}/users/xuid({xuid})/titleachievements?"
|
|
61
|
+
params = {"titleId": title_id}
|
|
62
|
+
resp = await self.client.session.get(
|
|
63
|
+
url,
|
|
64
|
+
params=params,
|
|
65
|
+
headers=self.HEADERS_GAME_360_PROGRESS,
|
|
66
|
+
rate_limits=self.rate_limit_read,
|
|
67
|
+
**kwargs,
|
|
68
|
+
)
|
|
69
|
+
resp.raise_for_status()
|
|
70
|
+
return Achievement360Response(**resp.json())
|
|
71
|
+
|
|
72
|
+
async def get_achievements_xbox360_earned(
|
|
73
|
+
self, xuid: str, title_id: str, **kwargs
|
|
74
|
+
) -> Achievement360Response:
|
|
75
|
+
"""
|
|
76
|
+
Get earned achievements for specific X360 title id
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
xuid (str): Xbox User Id
|
|
80
|
+
title_id (str): Xbox 360 Title Id
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
:class:`Achievement360Response`: Achievement 360 Response
|
|
84
|
+
"""
|
|
85
|
+
url = f"{self.ACHIEVEMENTS_URL}/users/xuid({xuid})/achievements?"
|
|
86
|
+
params = {"titleId": title_id}
|
|
87
|
+
resp = await self.client.session.get(
|
|
88
|
+
url,
|
|
89
|
+
params=params,
|
|
90
|
+
headers=self.HEADERS_GAME_360_PROGRESS,
|
|
91
|
+
rate_limits=self.rate_limit_read,
|
|
92
|
+
**kwargs,
|
|
93
|
+
)
|
|
94
|
+
resp.raise_for_status()
|
|
95
|
+
return Achievement360Response(**resp.json())
|
|
96
|
+
|
|
97
|
+
async def get_achievements_xbox360_recent_progress_and_info(
|
|
98
|
+
self, xuid: str, **kwargs
|
|
99
|
+
) -> Achievement360ProgressResponse:
|
|
100
|
+
"""
|
|
101
|
+
Get recent achievement progress and information
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
xuid (str): Xbox User Id
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
:class:`Achievement360Response`: Achievement 360 Response
|
|
108
|
+
"""
|
|
109
|
+
url = f"{self.ACHIEVEMENTS_URL}/users/xuid({xuid})/history/titles"
|
|
110
|
+
resp = await self.client.session.get(
|
|
111
|
+
url,
|
|
112
|
+
headers=self.HEADERS_GAME_360_PROGRESS,
|
|
113
|
+
rate_limits=self.rate_limit_read,
|
|
114
|
+
**kwargs,
|
|
115
|
+
)
|
|
116
|
+
resp.raise_for_status()
|
|
117
|
+
return Achievement360ProgressResponse(**resp.json())
|
|
118
|
+
|
|
119
|
+
async def get_achievements_xboxone_gameprogress(
|
|
120
|
+
self, xuid: str, title_id: str, **kwargs
|
|
121
|
+
) -> AchievementResponse:
|
|
122
|
+
"""
|
|
123
|
+
Get gameprogress for Xbox One title
|
|
124
|
+
|
|
125
|
+
Args:
|
|
126
|
+
xuid (str): Xbox User Id
|
|
127
|
+
title_id (str): Xbox One Title Id
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
:class:`AchievementResponse`: Achievement Response
|
|
131
|
+
"""
|
|
132
|
+
url = f"{self.ACHIEVEMENTS_URL}/users/xuid({xuid})/achievements?"
|
|
133
|
+
params = {"titleId": title_id}
|
|
134
|
+
resp = await self.client.session.get(
|
|
135
|
+
url,
|
|
136
|
+
params=params,
|
|
137
|
+
headers=self.HEADERS_GAME_PROGRESS,
|
|
138
|
+
rate_limits=self.rate_limit_read,
|
|
139
|
+
**kwargs,
|
|
140
|
+
)
|
|
141
|
+
resp.raise_for_status()
|
|
142
|
+
return AchievementResponse(**resp.json())
|
|
143
|
+
|
|
144
|
+
async def get_achievements_xboxone_recent_progress_and_info(
|
|
145
|
+
self, xuid: str, **kwargs
|
|
146
|
+
) -> RecentProgressResponse:
|
|
147
|
+
"""
|
|
148
|
+
Get recent achievement progress and information
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
xuid (str): Xbox User Id
|
|
152
|
+
|
|
153
|
+
Returns:
|
|
154
|
+
:class:`RecentProgressResponse`: Recent Progress Response
|
|
155
|
+
"""
|
|
156
|
+
url = f"{self.ACHIEVEMENTS_URL}/users/xuid({xuid})/history/titles"
|
|
157
|
+
resp = await self.client.session.get(
|
|
158
|
+
url,
|
|
159
|
+
headers=self.HEADERS_GAME_PROGRESS,
|
|
160
|
+
rate_limits=self.rate_limit_read,
|
|
161
|
+
**kwargs,
|
|
162
|
+
)
|
|
163
|
+
resp.raise_for_status()
|
|
164
|
+
return RecentProgressResponse(**resp.json())
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
from datetime import datetime, time
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel
|
|
5
|
+
|
|
6
|
+
from pythonxbox.common.models import CamelCaseModel
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class PagingInfo(CamelCaseModel):
|
|
10
|
+
continuation_token: str | None = None
|
|
11
|
+
total_records: int
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Achievement360(CamelCaseModel):
|
|
15
|
+
id: int
|
|
16
|
+
title_id: int
|
|
17
|
+
name: str
|
|
18
|
+
sequence: int
|
|
19
|
+
flags: int
|
|
20
|
+
unlocked_online: bool
|
|
21
|
+
unlocked: bool
|
|
22
|
+
is_secret: bool
|
|
23
|
+
platform: int
|
|
24
|
+
gamerscore: int
|
|
25
|
+
image_id: int
|
|
26
|
+
description: str
|
|
27
|
+
locked_description: str
|
|
28
|
+
type: int
|
|
29
|
+
is_revoked: bool
|
|
30
|
+
time_unlocked: datetime
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class Title360(CamelCaseModel):
|
|
34
|
+
last_played: datetime
|
|
35
|
+
current_achievements: int
|
|
36
|
+
current_gamerscore: int
|
|
37
|
+
sequence: int
|
|
38
|
+
title_id: int
|
|
39
|
+
title_type: int
|
|
40
|
+
platforms: list[int]
|
|
41
|
+
name: str
|
|
42
|
+
total_achievements: int
|
|
43
|
+
total_gamerscore: int
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class Achievement360Response(CamelCaseModel):
|
|
47
|
+
achievements: list[Achievement360]
|
|
48
|
+
paging_info: PagingInfo
|
|
49
|
+
version: datetime
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class Achievement360ProgressResponse(CamelCaseModel):
|
|
53
|
+
titles: list[Title360]
|
|
54
|
+
paging_info: PagingInfo
|
|
55
|
+
version: datetime
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class TitleAssociation(BaseModel):
|
|
59
|
+
name: str
|
|
60
|
+
id: int
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class Requirement(CamelCaseModel):
|
|
64
|
+
id: str
|
|
65
|
+
current: str | None = None
|
|
66
|
+
target: str
|
|
67
|
+
operation_type: str
|
|
68
|
+
value_type: str
|
|
69
|
+
rule_participation_type: str
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class Progression(CamelCaseModel):
|
|
73
|
+
requirements: list[Requirement]
|
|
74
|
+
time_unlocked: datetime
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class MediaAsset(BaseModel):
|
|
78
|
+
name: str
|
|
79
|
+
type: str
|
|
80
|
+
url: str
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class Reward(CamelCaseModel):
|
|
84
|
+
name: Any = None
|
|
85
|
+
description: Any = None
|
|
86
|
+
value: str
|
|
87
|
+
type: str
|
|
88
|
+
media_asset: Any = None
|
|
89
|
+
value_type: str
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class Achievement(CamelCaseModel):
|
|
93
|
+
id: str
|
|
94
|
+
service_config_id: str
|
|
95
|
+
name: str
|
|
96
|
+
title_associations: list[TitleAssociation]
|
|
97
|
+
progress_state: str
|
|
98
|
+
progression: Progression
|
|
99
|
+
media_assets: list[MediaAsset]
|
|
100
|
+
platforms: list[str]
|
|
101
|
+
is_secret: bool
|
|
102
|
+
description: str
|
|
103
|
+
locked_description: str
|
|
104
|
+
product_id: str
|
|
105
|
+
achievement_type: str
|
|
106
|
+
participation_type: str
|
|
107
|
+
time_window: Any = None
|
|
108
|
+
rewards: list[Reward]
|
|
109
|
+
estimated_time: time
|
|
110
|
+
deeplink: Any = None
|
|
111
|
+
is_revoked: bool
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class AchievementResponse(CamelCaseModel):
|
|
115
|
+
achievements: list[Achievement]
|
|
116
|
+
paging_info: PagingInfo
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class Title(CamelCaseModel):
|
|
120
|
+
last_unlock: datetime
|
|
121
|
+
title_id: int
|
|
122
|
+
service_config_id: str
|
|
123
|
+
title_type: str
|
|
124
|
+
platform: str
|
|
125
|
+
name: str
|
|
126
|
+
earned_achievements: int
|
|
127
|
+
current_gamerscore: int
|
|
128
|
+
max_gamerscore: int
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
class RecentProgressResponse(CamelCaseModel):
|
|
132
|
+
titles: list[Title]
|
|
133
|
+
paging_info: PagingInfo
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""
|
|
2
|
+
BaseProvider
|
|
3
|
+
|
|
4
|
+
Subclassed by every *real* provider
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import TYPE_CHECKING
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from pythonxbox.api.client import XboxLiveClient
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class BaseProvider:
|
|
15
|
+
def __init__(self, client: "XboxLiveClient") -> None:
|
|
16
|
+
"""
|
|
17
|
+
Initialize an the BaseProvider
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
client (:class:`XboxLiveClient`): Instance of XboxLiveClient
|
|
21
|
+
"""
|
|
22
|
+
self.client = client
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Store Catalog - Lookup Product Information
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from pythonxbox.api.provider.baseprovider import BaseProvider
|
|
6
|
+
from pythonxbox.api.provider.catalog.models import (
|
|
7
|
+
AlternateIdType,
|
|
8
|
+
CatalogResponse,
|
|
9
|
+
CatalogSearchResponse,
|
|
10
|
+
FieldsTemplate,
|
|
11
|
+
PlatformType,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class CatalogProvider(BaseProvider):
|
|
16
|
+
CATALOG_URL = "https://displaycatalog.mp.microsoft.com"
|
|
17
|
+
SEPERATOR = ","
|
|
18
|
+
|
|
19
|
+
async def get_products(
|
|
20
|
+
self,
|
|
21
|
+
big_ids: list[str],
|
|
22
|
+
fields: FieldsTemplate = FieldsTemplate.DETAILS,
|
|
23
|
+
**kwargs,
|
|
24
|
+
) -> CatalogResponse:
|
|
25
|
+
"""Lookup product by Big IDs."""
|
|
26
|
+
ids = self.SEPERATOR.join(big_ids)
|
|
27
|
+
params = {
|
|
28
|
+
"actionFilter": "Browse",
|
|
29
|
+
"bigIds": ids,
|
|
30
|
+
"fieldsTemplate": fields.value,
|
|
31
|
+
"languages": self.client.language.locale,
|
|
32
|
+
"market": self.client.language.short_id,
|
|
33
|
+
}
|
|
34
|
+
url = f"{self.CATALOG_URL}/v7.0/products"
|
|
35
|
+
resp = await self.client.session.get(
|
|
36
|
+
url, params=params, include_auth=False, **kwargs
|
|
37
|
+
)
|
|
38
|
+
resp.raise_for_status()
|
|
39
|
+
return CatalogResponse(**resp.json())
|
|
40
|
+
|
|
41
|
+
async def get_product_from_alternate_id(
|
|
42
|
+
self,
|
|
43
|
+
id: str,
|
|
44
|
+
id_type: AlternateIdType,
|
|
45
|
+
fields: FieldsTemplate = FieldsTemplate.DETAILS,
|
|
46
|
+
top: int = 25,
|
|
47
|
+
**kwargs,
|
|
48
|
+
) -> CatalogResponse:
|
|
49
|
+
"""Lookup product by Alternate ID."""
|
|
50
|
+
params = {
|
|
51
|
+
"top": top,
|
|
52
|
+
"alternateId": id_type.value,
|
|
53
|
+
"fieldsTemplate": fields.value,
|
|
54
|
+
"languages": self.client.language.locale,
|
|
55
|
+
"market": self.client.language.short_id,
|
|
56
|
+
"value": id,
|
|
57
|
+
}
|
|
58
|
+
url = f"{self.CATALOG_URL}/v7.0/products/lookup"
|
|
59
|
+
resp = await self.client.session.get(
|
|
60
|
+
url, params=params, include_auth=False, **kwargs
|
|
61
|
+
)
|
|
62
|
+
resp.raise_for_status()
|
|
63
|
+
return CatalogResponse(**resp.json())
|
|
64
|
+
|
|
65
|
+
async def product_search(
|
|
66
|
+
self,
|
|
67
|
+
query: str,
|
|
68
|
+
platform: PlatformType = PlatformType.XBOX,
|
|
69
|
+
top: int = 5,
|
|
70
|
+
**kwargs,
|
|
71
|
+
) -> CatalogSearchResponse:
|
|
72
|
+
"""Search for products by name."""
|
|
73
|
+
params = {
|
|
74
|
+
"languages": self.client.language.locale,
|
|
75
|
+
"market": self.client.language.short_id,
|
|
76
|
+
"platformdependencyname": platform.value,
|
|
77
|
+
"productFamilyNames": "Games,Apps",
|
|
78
|
+
"query": query,
|
|
79
|
+
"topProducts": top,
|
|
80
|
+
}
|
|
81
|
+
url = f"{self.CATALOG_URL}/v7.0/productFamilies/autosuggest"
|
|
82
|
+
resp = await self.client.session.get(
|
|
83
|
+
url, params=params, include_auth=False, **kwargs
|
|
84
|
+
)
|
|
85
|
+
resp.raise_for_status()
|
|
86
|
+
return CatalogSearchResponse(**resp.json())
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""Web API Constants."""
|
|
2
|
+
|
|
3
|
+
from pythonxbox.api.provider.catalog.models import AlternateIdType
|
|
4
|
+
|
|
5
|
+
HOME_APP_IDS = {
|
|
6
|
+
AlternateIdType.LEGACY_XBOX_PRODUCT_ID: "7b3ca835-5ef5-4d96-bc84-c1d8b5084236",
|
|
7
|
+
AlternateIdType.XBOX_TITLE_ID: "750323071",
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
SYSTEM_PFN_ID_MAP = {
|
|
11
|
+
"Microsoft.Xbox.LiveTV_8wekyb3d8bbwe": {
|
|
12
|
+
AlternateIdType.LEGACY_XBOX_PRODUCT_ID: "71e7df12-89e0-4dc7-a5ff-a182fc2df94f",
|
|
13
|
+
AlternateIdType.XBOX_TITLE_ID: "371594669",
|
|
14
|
+
},
|
|
15
|
+
}
|