1313import re
1414import pickle
1515
16+
1617def getAppPath ():
1718 applicationPath = os .path .expanduser ('~/Documents/NSO-RPC' )
1819 # Windows allows you to move your UserProfile subfolders, Such as Documents, Videos, Music etc.
@@ -21,14 +22,16 @@ def getAppPath():
2122 if platform .system () == 'Windows' :
2223 try :
2324 import ctypes .wintypes
24- CSIDL_PERSONAL = 5 # My Documents
25- SHGFP_TYPE_CURRENT = 0 # Get current, not default value
26- buf = ctypes .create_unicode_buffer (ctypes .wintypes .MAX_PATH )
25+ CSIDL_PERSONAL = 5 # My Documents
26+ SHGFP_TYPE_CURRENT = 0 # Get current, not default value
27+ buf = ctypes .create_unicode_buffer (ctypes .wintypes .MAX_PATH )
2728 ctypes .windll .shell32 .SHGetFolderPathW (None , CSIDL_PERSONAL , None , SHGFP_TYPE_CURRENT , buf )
28- applicationPath = os .path .join (buf .value ,'NSO-RPC' )
29- except :pass
29+ applicationPath = os .path .join (buf .value , 'NSO-RPC' )
30+ except :
31+ pass
3032 return applicationPath
3133
34+
3235def log (info , time = time .time ()):
3336 path = getAppPath ()
3437 if not os .path .isdir (path ):
@@ -37,6 +40,7 @@ def log(info, time = time.time()):
3740 file .write ('%s: %s\n ' % (time , info ))
3841 return info
3942
43+
4044def getVersion ():
4145 for i in range (5 ):
4246 try :
@@ -53,23 +57,25 @@ def getVersion():
5357 return ''
5458 return version [0 ]
5559
60+
5661client_id = '71b963c1b7b6d119'
5762version = 0.3
5863nsoAppVersion = None
59- languages = [ # ISO Language codes
60- 'en-US' ,
61- 'es-MX' ,
62- 'fr-CA' ,
63- 'ja-JP' ,
64- 'en-GB' ,
65- 'es-ES' ,
66- 'fr-FR' ,
67- 'de-DE' ,
68- 'it-IT' ,
69- 'nl-NL' ,
70- 'ru-RU'
64+ languages = [ # ISO Language codes
65+ 'en-US' ,
66+ 'es-MX' ,
67+ 'fr-CA' ,
68+ 'ja-JP' ,
69+ 'en-GB' ,
70+ 'es-ES' ,
71+ 'fr-FR' ,
72+ 'de-DE' ,
73+ 'it-IT' ,
74+ 'nl-NL' ,
75+ 'ru-RU'
7176]
7277
78+
7379class API ():
7480 def __init__ (self , session_token , user_lang , targetID , version ):
7581 pattern = re .compile (r'(\d.\d.\d)' )
@@ -142,7 +148,7 @@ def updateLogin(self):
142148 login = Login (self .userInfo , self .user_lang , self .accessToken , self .guid )
143149 login .loginToAccount ()
144150 try :
145- self .headers ['Authorization' ] = 'Bearer %s' % login .account ['result' ].get ('webApiServerCredential' ).get ('accessToken' ) # Add authorization token
151+ self .headers ['Authorization' ] = 'Bearer %s' % login .account ['result' ].get ('webApiServerCredential' ).get ('accessToken' ) # Add authorization token
146152 except Exception as e :
147153 raise Exception ('Failure with authorization: %s\n Login returns %s' % (e , login .account ))
148154 self .login = {
@@ -169,6 +175,7 @@ def getFriends(self):
169175 list .populateList (self )
170176 self .friends = list .friendList
171177
178+
172179class Nintendo ():
173180 def __init__ (self , sessionToken , userLang ):
174181 self .headers = {
@@ -190,6 +197,7 @@ def getServiceToken(self):
190197 response = requests .post (self .url + route , headers = self .headers , json = self .body )
191198 return json .loads (response .text )
192199
200+
193201class UsersMe ():
194202 def __init__ (self , accessToken , userLang ):
195203 self .headers = {
@@ -209,15 +217,17 @@ def get(self):
209217 response = requests .get (self .url + route , headers = self .headers )
210218 return json .loads (response .text )
211219
220+
212221class imink ():
213- def __init__ (self , id_token , timestamp , guid , iteration ):
222+ def __init__ (self , na_id , id_token , timestamp , guid , iteration ):
214223 self .headers = {
215224 'User-Agent' : 'NSO-RPC/%s' % version ,
216225 'Content-Type' : 'application/json; charset=utf-8' ,
217226 }
218227 self .body = {
219228 'token' : id_token ,
220- 'hashMethod' : str (iteration ),
229+ 'hash_method' : str (iteration ),
230+ 'na_id' : na_id ,
221231 }
222232
223233 self .url = 'https://api.imink.app'
@@ -229,6 +239,7 @@ def get(self):
229239 response = requests .post (self .url + route , headers = self .headers , data = json .dumps (self .body ))
230240 return json .loads (response .text )
231241
242+
232243class Login ():
233244 def __init__ (self , userInfo , userLang , accessToken , guid ):
234245 self .headers = {
@@ -245,13 +256,14 @@ def __init__(self, userInfo, userLang, accessToken, guid):
245256 }
246257
247258 self .url = 'https://api-lp1.znc.srv.nintendo.net'
248- self .timestamp = int (time .time ()) * 1000 # Convert from iOS to Android
259+ self .timestamp = int (time .time ()) * 1000 # Convert from iOS to Android
249260 self .guid = guid
250261
251262 self .userInfo = userInfo
252263 self .accessToken = accessToken
264+ self .na_id = userInfo ['id' ]
253265
254- self .imink = imink (self .accessToken , self .timestamp , self .guid , 1 ).get ()
266+ self .imink = imink (self .na_id , self . accessToken , self .timestamp , self .guid , 1 ).get ()
255267 self .timestamp = int (self .imink ['timestamp' ])
256268 self .guid = self .imink ['request_id' ]
257269
@@ -274,6 +286,7 @@ def loginToAccount(self):
274286 self .account = json .loads (response .text )
275287 return self .account
276288
289+
277290class User ():
278291 def __init__ (self , f ):
279292 self .id = f .get ('id' )
@@ -290,9 +303,10 @@ def __init__(self, f):
290303
291304 def description (self ):
292305 return ('%s (id: %s, nsaId: %s):\n ' % (self .name , self .id , self .nsaId )
293- + ' - Profile Picture: %s\n ' % self .imageUri
294- + ' - Status: %s\n ' % self .presence .description ()
295- )
306+ + ' - Profile Picture: %s\n ' % self .imageUri
307+ + ' - Status: %s\n ' % self .presence .description ()
308+ )
309+
296310
297311class Friend (User ):
298312 def __init__ (self , f ):
@@ -304,26 +318,28 @@ def __init__(self, f):
304318
305319 def description (self ):
306320 return ('%s (id: %s, nsaId: %s):\n ' % (self .name , self .id , self .nsaId )
307- + ' - Profile Picture: %s\n ' % self .imageUri
308- + ' - Is Favorite: %s\n ' % self .isFavoriteFriend
309- + ' - Friend Creation Date: %s\n ' % self .friendCreatedAt
310- + ' - Status: %s\n ' % self .presence .description ()
311- )
321+ + ' - Profile Picture: %s\n ' % self .imageUri
322+ + ' - Is Favorite: %s\n ' % self .isFavoriteFriend
323+ + ' - Friend Creation Date: %s\n ' % self .friendCreatedAt
324+ + ' - Status: %s\n ' % self .presence .description ()
325+ )
326+
312327
313328class FriendList ():
314329 def __init__ (self ):
315- self .route = '/v3/Friend/List' # Define API route
330+ self .route = '/v3/Friend/List' # Define API route
316331
317- self .friendList = [] # List of Friend object(s)
332+ self .friendList = [] # List of Friend object(s)
318333
319- def populateList (self , API :API ):
334+ def populateList (self , API : API ):
320335 response = API .makeRequest (self .route )
321336 try :
322337 arr = json .loads (response .text )['result' ]['friends' ]
323338 except Exception as e :
324339 log ('Failure with authorization: %s\Friends returns %s' % (e , response .text ))
325340 raise e
326- self .friendList = [ Friend (friend ) for friend in arr ]
341+ self .friendList = [Friend (friend ) for friend in arr ]
342+
327343
328344class Presence ():
329345 def __init__ (self , f ):
@@ -334,8 +350,9 @@ def __init__(self, f):
334350
335351 def description (self ):
336352 return ('%s (updatedAt: %s, logoutAt: %s)\n ' % (self .state , self .updatedAt , self .logoutAt )
337- + ' - Game: %s' % self .game .description ()
338- )
353+ + ' - Game: %s' % self .game .description ()
354+ )
355+
339356
340357class Game ():
341358 def __init__ (self , f ):
@@ -348,11 +365,12 @@ def __init__(self, f):
348365
349366 def description (self ):
350367 return ('%s (sysDescription: %s)\n ' % (self .name , self .sysDescription )
351- + ' - Game Icon: %s\n ' % self .imageUri
352- + ' - Shop Uri: %s\n ' % self .shopUri
353- + ' - Total Play Time: %s\n ' % self .totalPlayTime
354- + ' - First Played At: %s' % self .firstPlayedAt
355- )
368+ + ' - Game Icon: %s\n ' % self .imageUri
369+ + ' - Shop Uri: %s\n ' % self .shopUri
370+ + ' - Total Play Time: %s\n ' % self .totalPlayTime
371+ + ' - First Played At: %s' % self .firstPlayedAt
372+ )
373+
356374
357375class Session ():
358376 def __init__ (self ):
@@ -397,11 +415,11 @@ def run(self, code, verify):
397415 headers = self .headers
398416 headers .update ({
399417 'Accept-Language' : 'en-US' ,
400- 'Accept' : 'application/json' ,
401- 'Content-Type' : 'application/x-www-form-urlencoded' ,
402- 'Content-Length' : '540' ,
403- 'Host' : 'accounts.nintendo.com' ,
404- 'Connection' : 'Keep-Alive' ,
418+ 'Accept' : 'application/json' ,
419+ 'Content-Type' : 'application/x-www-form-urlencoded' ,
420+ 'Content-Length' : '540' ,
421+ 'Host' : 'accounts.nintendo.com' ,
422+ 'Connection' : 'Keep-Alive' ,
405423 })
406424 body = {
407425 'client_id' : client_id ,
0 commit comments