iksm_sessionをadbを介して取得するだけのpythonスクリプト
概要
以下のWebサイトに記載されている手順をある程度自動化したもの。
tryfreesoft.at.webry.info
このスクリプトがやること
スクリプトを実行する前の前準備
- Android SDK の導入
- adb接続が可能な Android端末を用意
- Android端末のローカルIPアドレス、ポート番号の調査
- Android端末でNintendo Switch Onlineをインストール、ログイン
筆者はWindows 7にAndroidエミュレーターの一種であるNoxPlayerをインストールして使用している。NoxPlayerを用いる場合の特有の注意点は次のとおり。
- Root化された端末ではNintendo Switch Onlineが起動できないため、ウィンドウの右上の歯車ボタン→通常設定 からRoot起動をオフにしておく。
- マルチインスタンスマネージャーにより複数の仮想端末を管理している場合、接続したい端末のポート番号やエイリアス名を事前に調べておく必要がある。以下のサイトが非常に参考になる。
スクリプト本体
import subprocess import time import datetime import threading import sqlite3 import tkinter from contextlib import closing # android のローカルIPアドレス、ポート番号 ADDR_ANDROID = "127.0.0.1:62001" # androidエミュレーターを起動するためのコマンド CMD_ANDROID = "C:\\Program Files (x86)\\Nox\\bin\\Nox.exe -clone:Nox_0" textBox = None labelText = None def guiStart(): global textBox global labelText root = tkinter.Tk() root.title("iksm_session getter") root.geometry("400x120") mainFrame = tkinter.Frame(root, bg="white") mainFrame.pack(fill = tkinter.BOTH, expand = True) textFrame = tkinter.Frame(mainFrame, width=400, height=40, bg="white") textFrame.pack() labelFrame = tkinter.Frame(mainFrame, bg="lightgray", relief = 'sunken', borderwidth = 2) labelFrame.pack(fill = tkinter.BOTH, expand = True) textBox = tkinter.Text(textFrame, height=1, width=48, bg="white") textBox.pack() button = tkinter.Button(textFrame, text=u'iksm_session取得', height=1) button.bind("<Button>",buttonClick) button.pack() # ラベルの文字列を変更したい場合はStringVarを割り当てる。 labelText = tkinter.StringVar() label = tkinter.Label(labelFrame, textvariable = labelText, height=2, anchor='n') label.pack(fill = tkinter.BOTH, expand = True) root.mainloop() def buttonClick(e): print(e) # バックグラウンドの処理は別スレッドで行わないと GUI が固まる。 threading.Thread(target=backStart).start() def backStart(): global textBox global labelText # android端末とroot権限で接続する。 # 接続に失敗したら端末を自前で起動しようとする。 while True: subprocess.call('adb connect ' + ADDR_ANDROID) # android端末が起動されていない場合、adb root で 1 が返ってくる。 returncode = subprocess.call('adb root') print("return code = ", returncode) if returncode == 1: labelText.set("Android端末に接続できません。\nNoxを起動します。") returncode = subprocess.Popen(CMD_ANDROID) print("return code = ", returncode) else: labelText.set("Android端末に接続完了。") break time.sleep(30) #Nintendo Switch Online の WebView のクッキーを5秒に一度取り出す。 while True: subprocess.call('adb pull /data/data/com.nintendo.znca/app_webview/Cookies Cookies.db') labelText.set("クッキー取得完了。") with closing(sqlite3.connect('Cookies.db')) as conn: c = conn.cursor() r = c.execute('select expires_utc, value from cookies where name = "iksm_session"').fetchall()[0] print(r) # chrome のクッキーは 1601/01/01 を起点としたUTC時刻で保存されている。 JST = datetime.timezone(datetime.timedelta(hours=+9), 'JST') now_utc = datetime.datetime.now(JST) d = datetime.datetime(1970, 1, 1, 0, 0, 0, 0) - datetime.datetime(1601, 1, 1, 0, 0, 0, 0) expires_utc = datetime.datetime.fromtimestamp(r[0]/1000000 - d.total_seconds(), JST) if expires_utc > now_utc: # 取り出したクッキーが現時点で有効だったらテキストエリアにiksm_sessionを格納しておしまい。 textBox.delete('1.0', tkinter.END) textBox.insert(tkinter.END, r[1]) labelText.set("iksm_session取得完了。") break else: labelText.set("クッキーの有効期限が切れています。\nNSO にログインし直してください。") time.sleep(5) if __name__ == '__main__': guiStart()