1
0
mirror of https://codeberg.org/vanous/huafetcher synced 2024-09-27 10:10:41 +02:00
huafetcher/main.py
2021-02-21 15:12:47 +01:00

503 lines
20 KiB
Python

from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.lang import Builder
from kivy.utils import platform
from kivy.uix.textinput import TextInput
from kivy.uix.boxlayout import BoxLayout
from functools import partial
from kivy.clock import Clock
from kivy.logger import Logger
from kivy.uix.dropdown import DropDown
from huami_token import HuamiAmazfit
import urls as urls
from kivy.core.clipboard import Clipboard
from kivy.storage.jsonstore import JsonStore
DEBUG=False
#DEBUG=True
def debug_print(*xargs):
if DEBUG:
print(*xargs)
SPACING=2
Builder.load_string('''
<MyInputy>:
font_size: 30
halign: 'left'
color: 1,1,1,1
bcolor: .1, 0, .6, 0
canvas.before:
Color:
rgba: root.bcolor
Rectangle:
size: (self.width -2, self.height -2)
pos: (self.x+1,self.y +1)
<MyLabel>:
font_size: 30
halign: 'center'
bcolor: .7, .7, .7, 1
canvas.before:
Color:
rgba: root.bcolor
Rectangle:
size: self.size
pos: self.pos
<MyLeftLabel>:
font_size: 30
halign: 'left'
bcolor: .7, .7, .7, 1
canvas.before:
Color:
rgba: root.bcolor
Rectangle:
size: self.size
pos: self.pos
<MyButton>:
font_size: 30
bcolor: .7, .7, .7, 1
background_color: .1, 0, .5, 0
canvas.before:
Color:
rgba: root.bcolor
Rectangle:
size: self.size
pos: self.pos
''')
class MyLabel(Label):
pass
class MyLeftLabel(Label):
pass
class MyButton(Button):
pass
class MyInput(TextInput):
pass
class Main(App):
def build(self):
self.huamidevice=HuamiAmazfit()
self.store = JsonStore('credentials.json')
screen_layout = BoxLayout(orientation="vertical", spacing=SPACING)
buttons_layout = BoxLayout(orientation="horizontal", spacing=SPACING)
rows_layout = BoxLayout(orientation="vertical", spacing=SPACING)
top_title_label=MyLeftLabel(text='Huafetcher', halign="left")
self.instructions_label=MyLeftLabel(text='Press "Get token", sign in, copy URL and paste here', halign="left", valign="middle", padding_x="20")
self.instructions_label.bind(size=self.instructions_label.setter('text_size'))
rows_layout.add_widget(top_title_label)
dropdown = DropDown()
xiaomi_button = MyButton(text='Xiaomi', size_hint_y=None, height=150)
xiaomi_button.bind(on_press=lambda a:self.set_login_method('xiaomi'))
xiaomi_button.bind(on_release=lambda btn: dropdown.select(btn.text))
amazfit_button = MyButton(text='Amazfit', size_hint_y=None, height=150)
amazfit_button.bind(on_press=lambda a:self.set_login_method('amazfit'))
amazfit_button.bind(on_release=lambda btn: dropdown.select(btn.text))
dropdown.add_widget(xiaomi_button)
dropdown.add_widget(amazfit_button)
dropdown_button = MyButton(text='Login method')
dropdown_button.bind(on_release=dropdown.open)
#dropdown_button.bind(on_press=lambda x: setattr(dropdown_button,'text','Select'))
dropdown.bind(on_select=lambda instance, x: setattr(dropdown_button, 'text', x))
self.get_token_button = MyButton(text='Get token')
self.get_token_button.bind(on_press=self.on_press_button_gettoken)
self.fetch_key_button = MyButton(text='Fetch key')
self.fetch_key_button.bind(on_press=self.on_press_button_fetch_key)
self.fetch_key_button.disabled=True
self.fetch_agps_button = MyButton(text='Fetch aGPS')
self.fetch_agps_button.bind(on_press=self.on_press_button_agps)
self.fetch_agps_button.disabled=True
share_agps_button = MyButton(text='Share aGPS')
share_agps_button.bind(on_press=self.on_press_button_share_agps)
buttons_layout.add_widget(self.get_token_button)
#buttons_layout.add_widget(login_button)
buttons_layout.add_widget(self.fetch_key_button)
buttons_layout.add_widget(self.fetch_agps_button)
#sharing doesn't work
#buttons_layout.add_widget(share_agps_button)
self.paste_token_input_layout = BoxLayout(orientation="horizontal", spacing=SPACING)
paste_token_input_label=MyLabel(text='URL result')
self.paste_token_input_layout.disabled=True
self.paste_token_input = MyInput(text='',
multiline=False,
)
self.paste_token_input.bind(text=self.set_token)
paste_token_url_button=MyButton(text='Paste', size_hint=(.3, 1))
paste_token_url_button.bind(on_press=lambda instance: self.on_press_paste(self.paste_token_input) )
self.paste_token_input_layout.add_widget(paste_token_input_label)
self.paste_token_input_layout.add_widget(paste_token_url_button)
self.paste_token_input_layout.add_widget(self.paste_token_input)
credentials_email_label=MyButton(text='Email' , size_hint=(.7, 1))
self.credentials_email_input = MyInput(text='',
multiline=False,
)
self.credentials_email_input.bind(text=lambda instance,x: setattr(self.huamidevice,'email',x))
email_paste_button=MyButton(text='Paste', size_hint=(.3, 1))
email_paste_button.bind(on_press=lambda instance: self.on_press_paste(self.credentials_email_input) )
email_save_button=MyButton(text='Save', size_hint=(.3, 1))
#load_button1.bind(on_press=lambda instance: )
email_save_button.bind(on_press=lambda instance: self.on_press_save(self.credentials_email_input, 'email') )
self.credentials_email_layout = BoxLayout(orientation="horizontal", spacing=SPACING)
self.credentials_email_layout.add_widget(credentials_email_label)
#credentials_email_layout.add_widget(load_button1)
self.credentials_email_layout.add_widget(email_save_button)
self.credentials_email_layout.add_widget(email_paste_button)
self.credentials_email_layout.add_widget(self.credentials_email_input)
credentials_password_label=MyLabel(text='Password', size_hint=(.7, 1))
self.credentials_password_input = MyInput(text='',
multiline=False,
)
self.credentials_password_input.bind(text=lambda instance,x: setattr(self.huamidevice,'password',x))
credentials_password_label.bind(on_press=self.on_press_paste_password)
password_paste_button=MyButton(text='Paste', size_hint=(.3, 1))
password_paste_button.bind(on_press=lambda instance: self.on_press_paste(self.credentials_password_input) )
password_save_button=MyButton(text='Save', size_hint=(.3, 1))
password_save_button.bind(on_press=lambda instance: self.on_press_save(self.credentials_password_input, 'password') )
self.credentials_password_layout = BoxLayout(orientation="horizontal", spacing=SPACING)
self.credentials_password_layout.add_widget(credentials_password_label)
self.credentials_password_layout.add_widget(password_save_button)
self.credentials_password_layout.add_widget(password_paste_button)
self.credentials_password_layout.add_widget(self.credentials_password_input)
rows_layout.add_widget(dropdown_button)
rows_layout.add_widget(self.credentials_email_layout)
rows_layout.add_widget(self.credentials_password_layout)
rows_layout.add_widget(self.paste_token_input_layout)
result_value_label=MyButton(text='Found key')
self.result_value_value=TextInput()
copy_key_button=MyButton(text='Copy', size_hint=(.3, 1))
copy_key_button.bind(on_press=lambda instance: self.on_press_copy(self.result_value_value) )
self.result_value_layout = BoxLayout(orientation="horizontal", spacing=SPACING)
self.result_value_layout.add_widget(result_value_label)
self.result_value_layout.add_widget(copy_key_button)
self.result_value_layout.add_widget(self.result_value_value)
result_value_label.bind(on_press=self.on_press_copy_result)
self.result_value_layout.disabled=True
rows_layout.add_widget(self.result_value_layout)
rows_layout.add_widget(buttons_layout)
rows_layout.add_widget(self.instructions_label)
screen_layout.add_widget(rows_layout)
self.on_press_load(self.credentials_email_input, 'email')
self.on_press_load(self.credentials_password_input, 'password')
#self.set_login_method('xiaomi')
#dropdown_button.text='Xiaomi'
self.set_login_method('amazfit')
dropdown_button.text='Amazfit'
return screen_layout
def set_visibility(self, widget_id, hide=True):
debug_print(hide)
if hasattr(widget_id, 'saved_attrs'):
debug_print(widget_id.saved_attrs)
if not hide:
widget_id.height, widget_id.size_hint_y, widget_id.opacity, widget_id.disabled = widget_id.saved_attrs
del widget_id.saved_attrs
elif hide:
widget_id.saved_attrs = widget_id.height, widget_id.size_hint_y, widget_id.opacity, widget_id.disabled
widget_id.height, widget_id.size_hint_y, widget_id.opacity, widget_id.disabled = 0, None, 0, True
def set_login_method(self,method):
debug_print(method)
self.huamidevice.method=method
if method == 'xiaomi':
self.instructions_label.text='Press "Get token", sign in, copy URL and paste here'
self.set_visibility(self.credentials_email_layout, hide=True)
self.set_visibility(self.credentials_password_layout, hide=True)
self.set_visibility(self.paste_token_input_layout, hide=False)
self.set_visibility(self.result_value_layout, hide=False)
self.get_token_button.disabled=False
self.fetch_agps_button.disabled=True
self.fetch_key_button.disabled=True
else: #amazfit
self.instructions_label.text='Email and password must be filled, then use Fetch key or Fetch aGPS'
self.set_visibility(self.credentials_email_layout, hide=False)
self.set_visibility(self.credentials_password_layout, hide=False)
self.set_visibility(self.paste_token_input_layout, hide=True)
#self.set_visibility(self.result_value_layout, hide=True)
self.get_token_button.disabled=True
self.fetch_agps_button.disabled=False
self.fetch_key_button.disabled=False
def set_token(self, instance, text):
debug_print("got", text)
debug_print(self.huamidevice)
self.huamidevice.parse_token(text)
debug_print(self.huamidevice)
if self.huamidevice.access_token is not None:
self.fetch_agps_button.disabled=False
self.fetch_key_button.disabled=False
self.instructions_label.text='now press "Fetch key" or "Fetch aGPS"'
else:
if self.paste_token_input_layout.disabled==False:
self.instructions_label.text='token not found in the url, repeat sign in a copy/paste url'
def on_press_button_gettoken(self, instance):
debug_print('You pressed the button login!')
self.result_value_value.text=''
self.paste_token_input.text=''
self.fetch_agps_button.disabled=True
self.fetch_key_button.disabled=True
self.result_value_layout.disabled=True
self.instructions_label.text="log in and paste url here"
debug_print(self.huamidevice)
if self.huamidevice.method == 'xiaomi':
self.instructions_label.text="log in and paste url here"
login_url = urls.URLS["login_xiaomi"]
if ( platform != 'android' ):
import webbrowser
webbrowser.open(login_url, new = 2)
else:
from jnius import autoclass
from jnius import cast
PythonActivity = autoclass('org.kivy.android.PythonActivity')
Intent = autoclass('android.content.Intent')
Uri = autoclass('android.net.Uri')
intent = Intent()
intent.setAction(Intent.ACTION_VIEW)
intent.setData(Uri.parse(login_url))
currentActivity = cast('android.app.Activity', PythonActivity.mActivity)
currentActivity.startActivity(intent)
self.paste_token_input_layout.disabled=False
return
else:
#login method amazfit
try:
res=self.huamidevice.get_access_token()
print("amazfit get access token result", res)
if res:
#if self.huamidevice.user_id is not None:
# self.instructions_label.text="Signed in as: {}, getting data".format(self.huamidevice.user_id)
#else:
# self.instructions_label.text="You must sign in first"
self.fetch_key_button.disabled=False
self.fetch_agps_button.disabled=False
except Exception as e:
debug_print(e)
self.instructions_label.text=f"{e}"
def on_press_button_fetch_key(self, instance):
debug_print('You pressed the button fetch!')
if self.huamidevice.method=='amazfit':
res=False
try:
res=self.huamidevice.get_access_token()
except Exception as e:
debug_print(e)
self.instructions_label.text=f"{e}"
if not res:
self.instructions_label.text="amazfit login failed"
self.result_value_value.text=''
self.paste_token_input.text=''
self.result_value_layout.disabled=True
self.paste_token_input_layout.disabled=True
if self.huamidevice.method!='amazfit':
self.fetch_key_button.disabled=True
self.fetch_agps_button.disabled=True
debug_print(self.huamidevice)
self.instructions_label.text="signing in and getting keys"
Clock.schedule_once(self.fetch_keys, 1)
def fetch_keys(self, *xargs):
try:
res=self.huamidevice.login()
if res:
self.instructions_label.text="Signed in as: {}, getting data".format(self.huamidevice.user_id)
except Exception as e:
debug_print(e)
self.instructions_label.text=f"{e}"
return
device_keys = self.huamidevice.get_wearable_auth_keys()
self.result_value_layout.disabled=False
self.result_value_value.text=""
key=""
for device_key in device_keys:
debug_print(f"{device_key} {device_keys[device_key]}")
key=f"{device_key} {device_keys[device_key]}"
if key=="":
self.instructions_label.text="No keys on the server"
else:
self.instructions_label.text="Got the key, use the Copy button"
self.result_value_value.text=f"{key}"
#Clock.schedule_once(partial(self.doit), 1)
def on_press_paste_token(self, instance):
self.paste_token_input.text=Clipboard.paste()
def on_press_paste_email(self, instance):
self.credentials_email_input.text=Clipboard.paste()
def on_press_paste_password(self, instance):
self.credentials_password_input.text=Clipboard.paste()
def on_press_copy_result(self, instance):
Clipboard.copy(self.result_value_value.text)
def on_press_paste(self, instance):
instance.text=Clipboard.paste()
def on_press_copy(self, instance):
Clipboard.copy(instance.text)
self.instructions_label.text='value copied to clipboard'
def on_press_load(self, instance, key):
if self.store.exists(key):
instance.text=self.store.get(key)["value"]
def on_press_save(self, instance, key):
self.store.put(key, value=instance.text)
def on_press_button_agps(self, instance):
debug_print('You pressed the button agps!')
if self.huamidevice.method=='amazfit':
res=False
try:
res=self.huamidevice.get_access_token()
except Exception as e:
debug_print(e)
self.instructions_label.text=f"{e}"
if not res:
self.instructions_label.text="amazfit login failed"
self.result_value_value.text=''
self.paste_token_input.text=''
self.result_value_layout.disabled=True
self.paste_token_input_layout.disabled=True
if self.huamidevice.method!='amazfit':
self.fetch_key_button.disabled=True
self.fetch_agps_button.disabled=True
debug_print(self.huamidevice)
self.instructions_label.text="signing in and getting files"
Clock.schedule_once (self.get_agps_files, 1)
def get_agps_files(self, *xargs):
import zipfile
try:
res=self.huamidevice.login()
if res:
self.instructions_label.text="Signed in as: {}, getting data".format(self.huamidevice.user_id)
except Exception as e:
debug_print(e)
self.instructions_label.text=f"{e}"
return
self.huamidevice.get_gps_data()
agps_file_names = ["cep_alm_pak.zip"]
if ( platform == 'android' ):
import shutil
import os
from jnius import autoclass
from jnius import cast
Environment = autoclass('android.os.Environment')
File = autoclass('java.io.File')
data_dir = Environment.getExternalStorageDirectory().getPath()
debug_print(data_dir)
for filename in agps_file_names:
sdpathfile = os.path.join(data_dir, filename)
shutil.copyfile(filename, sdpathfile)
with zipfile.ZipFile(filename, "r") as zip_f:
#zip_f.extractall()
zip_f.extractall(data_dir)
self.instructions_label.text="Files downloaded and extracted"
#Clock.schedule_once(partial(self.doit), 1)
def on_press_button_share_agps(self, instance):
#not working because android broke it
if ( platform == 'android' ):
import os
from jnius import autoclass
from jnius import cast
Environment = autoclass('android.os.Environment')
File = autoclass('java.io.File')
data_dir = Environment.getExternalStorageDirectory().getPath()
PythonActivity = autoclass('org.kivy.android.PythonActivity')
Intent = autoclass('android.content.Intent')
Uri = autoclass('android.net.Uri')
intent = Intent()
intent.setAction(Intent.ACTION_VIEW)
data_dir = getattr(self, 'user_data_dir')
file_target=File(os.path.join(data_dir, "cep_pak.bin"))
#target=Uri.parse(os.path.join("file:///", data_dir, "cep_pak.bin"))
target=Uri.fromFile(file_target)
#intent.setData(Uri.parse(os.path.join("file:///", data_dir, "cep_pak.bin")))
#intent.setType("application/octet-stream")
intent.setDataAndType(target, "application/octet-stream")
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
currentActivity = cast('android.app.Activity', PythonActivity.mActivity)
currentActivity.startActivity(intent)
#intent = Intent()
#intent.setAction(Intent.ACTION_VIEW)
#intent.setData(Uri.parse("gps_alm.bin"))
#currentActivity = cast('android.app.Activity', PythonActivity.mActivity)
#currentActivity.startActivity(intent)
#def doit(self, *kargs):
def openweb(url):
debug_print("open ", url)
if __name__ == '__main__':
app = Main()
app.run()