From e48c22e0f7d94323d70b78d2cf9f149dbf06ebf7 Mon Sep 17 00:00:00 2001 From: William Bruno Date: Wed, 29 Apr 2026 13:19:28 -0400 Subject: [PATCH] Added Favorites to geocache.db (needs rework) and more --- cookies/willbrunogmailcom.cookiejar | 36 ++--- cookies/willbrunogmailcom.session | 2 +- geocache.db | Bin 90112 -> 208896 bytes src/pymd3_vue_location_sim/geo_cache.py | 80 +++++++++-- src/pymd3_vue_location_sim/server.py | 181 ++++++++++++++++++++++-- 5 files changed, 263 insertions(+), 36 deletions(-) diff --git a/cookies/willbrunogmailcom.cookiejar b/cookies/willbrunogmailcom.cookiejar index bb7e4cc..84f748f 100644 --- a/cookies/willbrunogmailcom.cookiejar +++ b/cookies/willbrunogmailcom.cookiejar @@ -1,24 +1,24 @@ #LWP-Cookies-2.0 Set-Cookie3: dslang=US-EN; path="/"; domain=.apple.com; path_spec; secure; discard; HttpOnly=None; version=0 Set-Cookie3: site=USA; path="/"; domain=.apple.com; path_spec; secure; discard; HttpOnly=None; version=0 -Set-Cookie3: acn01=KVgOa2TlSALDmkRBN3HjFqQsmjntJ3LJQtZC9wATSlL+oYci; path="/"; domain=.apple.com; path_spec; secure; expires="2027-04-21 18:02:51Z"; HttpOnly=None; version=0 -Set-Cookie3: aasp=97997103CCD7FEC9173190AED7457252EBCD7B770AB7B784C902761FC601C83B02A28C2DE1B84D51A690620FBBE43A9F53E20534400A5BABA174C06BCDF6D1239746712B62A97006E8A95F03A96A584A7185B1EB24404B0F03A152E9F46C23451139DEBF74FACF2C476512DC59E85823694E20CF535BBE50; path="/"; domain=.idmsa.apple.com; path_spec; secure; discard; HttpOnly=None; version=0 +Set-Cookie3: acn01=70L4mLhmweVoXyGsy5nJlIQubkrJOwRcyl3qLwAVJO5xpjKw; path="/"; domain=.apple.com; path_spec; secure; expires="2027-04-29 16:06:06Z"; HttpOnly=None; version=0 +Set-Cookie3: aasp=3C2D0B45AFDCBAC81490E66E2DB79DD28298FB98A4E44381F64D4CFC4A677C6E4BE90E2B7F77BAFC992186F745E8A39EC5B52EE814BB65F1BA8137C80C973C9B657E1300A0E9C22BE32927B428866415AE2E3E66BA4541A67D8411C808E20F8797B807AEB5BDEDA05F2B6FF1306E59D4212F589D7028ED1B; path="/"; domain=.idmsa.apple.com; path_spec; secure; discard; HttpOnly=None; version=0 Set-Cookie3: X-APPLE-UNIQUE-CLIENT-ID="\"BA==\""; path="/"; domain=.icloud.com; path_spec; domain_dot; secure; discard; version=0 -Set-Cookie3: X-APPLE-WEBAUTH-LOGIN="\"v=1:t=BA==BST_IAAAAAAABLwIAAAAAGnnu8wRDmdzLmljbG91ZC5hdXRovQDEXUpbkZ6MgVpJex6704NeoKMirs7DTjQaMiLP3D7RDPPgRrN1eyRakxlhJwOczfTWOBtEP6_JywPTG3CmSA0RzajX5msyXsLEbn2K7IC-IF2NRP6-O8ACrZc8NLmZhrpYcMuYd7-cRNCfP9YrPhaLOOIYjQ~~\""; path="/"; domain=.icloud.com; path_spec; domain_dot; secure; discard; HttpOnly=None; version=0 -Set-Cookie3: X-APPLE-WEBAUTH-VALIDATE="\"v=1:t=BA==BST_IAAAAAAABLwIAAAAAGnnu8wRDmdzLmljbG91ZC5hdXRovQDEXUpbkZ6MgVpJex6704NeoKMirs7DTjQaMiLP3D7RDPPgRrN1eyRakxlhJwOczfTWOBtEP6_JywPTG3CmSA0RzajX5msyXsLEbn2K7IC-IHq8h87PbRbxm_5NFEGqbnrBegyo4fAVl3K0v8zi4ALPFmK-uw~~\""; path="/"; domain=.icloud.com; path_spec; domain_dot; secure; discard; version=0 -Set-Cookie3: X-APPLE-WEBAUTH-USER="\"v=1:s=1:d=157320350\""; path="/"; domain=.icloud.com; path_spec; domain_dot; secure; expires="2026-05-21 18:02:55Z"; HttpOnly=None; version=0 +Set-Cookie3: X-APPLE-WEBAUTH-LOGIN="\"v=1:t=BA==BST_IAAAAAAABLwIAAAAAGnyLG8RDmdzLmljbG91ZC5hdXRovQB9kwQUaVp5mcYpwvOxZ4GCnC3PL21rIb1KWfwqyYi3lai2xZjOlnV9toJ7ElKE2hRWdegjf6QPvLBIR3qtNxAV8sYd2zZVy7HQj1jd0bSMIj1lQH17O7vZ7UZ9V4sjGYCoYe1OO4jPyE8NLSEv-apjhUGiMg~~\""; path="/"; domain=.icloud.com; path_spec; domain_dot; secure; discard; HttpOnly=None; version=0 +Set-Cookie3: X-APPLE-WEBAUTH-VALIDATE="\"v=1:t=BA==BST_IAAAAAAABLwIAAAAAGnyLG8RDmdzLmljbG91ZC5hdXRovQB9kwQUaVp5mcYpwvOxZ4GCnC3PL21rIb1KWfwqyYi3lai2xZjOlnV9toJ7ElKE2hRWdegjf6QPvLBIR3qtNxAV8sYd2zZVy7HQj1jd0bSMIuKq-K9HG0t1RhYt6T0QyYD3uOqatUxNZx7ujEE75WQMFsa6eg~~\""; path="/"; domain=.icloud.com; path_spec; domain_dot; secure; discard; version=0 +Set-Cookie3: X-APPLE-WEBAUTH-USER="\"v=1:s=1:d=157320350\""; path="/"; domain=.icloud.com; path_spec; domain_dot; secure; expires="2026-05-29 16:06:09Z"; HttpOnly=None; version=0 Set-Cookie3: X_APPLE_WEB_KB-FHMLYL_TPMN_3A8D3KIPPI0C_EC="\"v=1:t=BA==BST_IAAAAAAABLwIAAAAAGm_OLQRDmdzLmljbG91ZC5hdXRovQD38nYoxQenHW9WggeFKkoDa8I8zeKoOshv6I4dsZQalR2itry1r6kUZe9d_BZan1W-oKlImTrYi_-Vt5Q4YEJWJITWeqN8QChxvbTXB0o8sQ-wAIzBL1J5sQIRBqMadrtP5U0wslkRg0u0AguK20CM4TGoGg~~\""; path="/"; domain=.icloud.com; path_spec; domain_dot; secure; expires="2026-05-21 00:32:52Z"; HttpOnly=None; version=0 -Set-Cookie3: X-APPLE-DS-WEB-SESSION-TOKEN="\"AQGaLX9cVeJ7EnQI/NCzMqxhb2pDyS9YSfQ1UGym2zF1fVrljZeKrlUA3e7k6IbGJwPd7ssN4+feYO2egAdRyJhQ0LJ89jY0jkyCAahyW4neQn/tbHwb49oChj+vjIK0Yv52Y3293nImzWSw1iUtNL6EhIgISPRk47tBH3PrEPwaFuPEK+YtFT8TeKaAWdIbXRIGxBkYEJYyl8BUFt4dobnS2shzOX7dfjOaBKClBF4y2x3/EVb6TeR6+kBoyLbZHe0+RMvyqrO0FFhCagmUZ0+xPAABPJq4r4JTmVfvKOU6j5gPO9Jsz97Damf9G6QyaqKcy4MjSmow4v+diEVaUdR4HyByCRTYcH+biNLnoVBeSPoVIuUQAlqdcDry6epZquivcATUeCUBEMroSWRz6gdLWkdCMSGqP+TR+aV0VROoJkGjT3lKlOJ4ElgfD5aQh4PHKyg70o9K5Eq8C+nMlphuFAgPVypRYL5rDebOWBfIlJRNuUSUIvvVyiBq94Ii2YI8BwX07TdZszdPj9oHtnX264nZe3YUw4W9XCkdPDufluUzFIP3bMIifRrOk6yEbXObUjbf5POU1taM6S2zaMvN7GspAkV5FvYE+E2NHRPGGq8PZ+8fqSIAdOx+O+zQq9T69NmxpvloIZYAUZUlwjOFtXr3vfHQhik82eLifYuiqsp/9M4yDIJvQfC7H6Mc4aM4aNHfHt2BdgXaRR2Zsx35CKLCKQtxpqT5DdO3y4+dDZt/Le7lIF/N\""; path="/"; domain=.icloud.com; path_spec; domain_dot; secure; expires="2026-05-21 18:02:55Z"; HttpOnly=None; version=0 +Set-Cookie3: X-APPLE-DS-WEB-SESSION-TOKEN="\"AQHabF8DfZ/FjCaFRDyaWdhzHLkfHKJ7x4QBikmeVCkCi4UMOxseAhL0l4roIVCB5CcjlGwqkXkBR30TGViREh5tXUpcTxlPXuZU4BGrwkUfXZmLxgLIAdfx6GEmbRfNzjH043ONXOYRRhsdAzTdC1atFGVUWrY3Vbvmd3QkTA8SB2UmTgVqgZ76mz7+rN5c5qeFm3YU66xjGTYrEAmzB2McNoXQSzq0lXBEWtBCMAVcr2VdIYkKOIPXUO0RL8w7k0++xh5Ci4uIggcArg1NJSF8l58yZ3P3CGZhVHigMgTE9/cKniRMPprV6mjyeWV7hU+HyFyspGvSTEk7vMXiyub/64bI/6wzsJFdm8WKXIJq9rok1KGZmO8mu3Nw8oeMRW2Ee45FRChCwzixHHhmEmd6z3OnJUZabRjo8XqAfR3Iq84PgDu8VxkONvfng4YZgxlqv0rSzZ5lI6+BX6Z2nJoH5kOw//L7t6XfgEL2zBmlWR9VY1GOlTEcA2+tfsoVWKkjk0Fhuum72fnuTeIsu1WNLi3noE8zYaSEAwzGw/vw95wr5JGodpm5pRvr0BauTKJEFUmb4FGTeh7ajE5/wrJzvFV9EyT3nc3WWrtjOXU+lCXGZNMZUbBnOdQh3X6KZw9zK16d8RJTkQ9eZc5p5RIShtAz+G0sBqo/Eu+m3e9GnRsrFafZF/oTjN4w/kCfqGzi/L59d5uCX8qYgmm1GgB7lffSaZS+gsNHVrGU7R3VaUQCbeQ=\""; path="/"; domain=.icloud.com; path_spec; domain_dot; secure; expires="2026-05-29 16:06:09Z"; HttpOnly=None; version=0 Set-Cookie3: X-APPLE-WEBAUTH-HSA-TRUST="\"28a33818a1dce9a0eecde38e7c8fcc6f080b70bc9feb505599fb2855903a4792_HSARMTKNSRVXWFlajR2ecD1662phQjqU9vXxnL49ZjypuVYYXHDpA3wTiX6Mf2J4WDlIhZj52z81aDOuz+VC80bVhV41TSNN4ggoPjW8WnsQrjniTQYkgJycPQNnzhkK4hfe2AMrr/bhrJJm8sHHc+Oh1HUckN6T7T4c1bmf2Qg9tRwsdRDNyMMyFH/Ml/cQlWKj39/YHlY=SRVX\""; path="/"; domain=.icloud.com; path_spec; domain_dot; secure; expires="2026-07-19 17:15:45Z"; HttpOnly=None; version=0 -Set-Cookie3: X-APPLE-WEBAUTH-PCS-Events="\"S2V5QXBwbDoBAAAA8QRuAAD03QLs6kAdJCQM23wVykZFD0clWmO+gTubXQ9MuQcaLA==\""; path="/"; domain=.icloud.com; path_spec; domain_dot; secure; expires="2026-05-21 18:02:55Z"; HttpOnly=None; version=0 -Set-Cookie3: X-APPLE-WEBAUTH-PCS-Documents="\"S2V5QXBwbDoBAAAAAgRuAAAy5taxxsiD1jDBrDQrQ1SiNyKmIxvvaWA7D0nA4Dl1iw==\""; path="/"; domain=.icloud.com; path_spec; domain_dot; secure; expires="2026-05-21 18:02:55Z"; HttpOnly=None; version=0 -Set-Cookie3: X-APPLE-WEBAUTH-PCS-Photos="\"S2V5QXBwbDoBAAAAAwRuAADS4+q95r+DyWl1ZGAmQT9MS2LUEBKAYun3XGW61iPTXg==\""; path="/"; domain=.icloud.com; path_spec; domain_dot; secure; expires="2026-05-21 18:02:55Z"; HttpOnly=None; version=0 -Set-Cookie3: X-APPLE-WEBAUTH-PCS-Cloudkit="\"S2V5QXBwbDoBAAAABARuAABOeS5LblTFkG8u6j7mIwaaRXTJwPVJ0sZ8/g9jV8910g==\""; path="/"; domain=.icloud.com; path_spec; domain_dot; secure; expires="2026-05-21 18:02:55Z"; HttpOnly=None; version=0 -Set-Cookie3: X-APPLE-WEBAUTH-PCS-Safari="\"S2V5QXBwbDoBAAAAFgRuAABsSNg/+jBeWh2M6qOISYiUBEq79JiSuu7otGjyBpBf4Q==\""; path="/"; domain=.icloud.com; path_spec; domain_dot; secure; expires="2026-05-21 18:02:55Z"; HttpOnly=None; version=0 -Set-Cookie3: X-APPLE-WEBAUTH-PCS-Mail="\"S2V5QXBwbDoBAAAABwRuAADF1hkuqi8C9dtlFR42VnoNAyVPpWhcrELIRAjf+N3M0g==\""; path="/"; domain=.icloud.com; path_spec; domain_dot; secure; expires="2026-05-21 18:02:55Z"; HttpOnly=None; version=0 -Set-Cookie3: X-APPLE-WEBAUTH-PCS-Notes="\"S2V5QXBwbDoBAAAACQRuAACUkk2Drkms4w+Wh9VFeFzbkOOMxla+5RXOacqRl/OT5A==\""; path="/"; domain=.icloud.com; path_spec; domain_dot; secure; expires="2026-05-21 18:02:55Z"; HttpOnly=None; version=0 -Set-Cookie3: X-APPLE-WEBAUTH-PCS-News="\"S2V5QXBwbDoBAAAACwRuAACI8hcv3wQKVQc/jrosTdSeaOV7wKGolh3SsnB2KV4l5Q==\""; path="/"; domain=.icloud.com; path_spec; domain_dot; secure; expires="2026-05-21 18:02:55Z"; HttpOnly=None; version=0 -Set-Cookie3: X-APPLE-WEBAUTH-PCS-Sharing="\"S2V5QXBwbDoBAAAADARuAAAMNHurlvF3BExXBzOliO8/XXMKPJVICVoKrapQdZ6DtA==\""; path="/"; domain=.icloud.com; path_spec; domain_dot; secure; expires="2026-05-21 18:02:55Z"; HttpOnly=None; version=0 -Set-Cookie3: X-APPLE-WEBAUTH-TOKEN="\"v=2:t=BA==BST_IAAAAAAABLwIAAAAAGnoSj8RDmdzLmljbG91ZC5hdXRovQBIW8hdgh_zfyx02_y4Hn4HvHqQgiLD7363DvLz7pwBtrTvdm3V7I3ffhB0g2EHzkFt1dIaDrk1sdCY46eySjfCpcSrwcRxUhMWIuvWzV4dvZbUKrHr4X5v98wrzMX-Xwvwo1OOFuv04U9NhQTZqEdQF22Oeg~~\""; path="/"; domain=.icloud.com; path_spec; domain_dot; secure; expires="2026-05-06 04:10:39Z"; HttpOnly=None; version=0 -Set-Cookie3: X-APPLE-WEBAUTH-FMIP="\"BA==BST_IAAAAAAABLwIAAAAAGnoSj8RDmdzLmljbG91ZC5hdXRovQBIW8hdgh_zfyx02_y4Hn4HvHqQgiLD7363DvLz7pwBtrTvdm3V7I3ffhB0g2EHzkFt1dIaDrk1sdCY46eySjfCpcSrwcRxUhMWIuvWzV4dvbKKudZw4ESK__dFUngctbzufvHZm3Ik0x6Ql7094pfT7Iuo-Q~~\""; path="/"; domain=.icloud.com; path_spec; domain_dot; secure; discard; HttpOnly=None; version=0 -Set-Cookie3: xr_3n2093n1a="tF9S/YsknhHffdhwA1W+2NKKwF/D5M+PVtX/BUh5l6Q="; path="/"; domain=p144-fmipweb.icloud.com; path_spec; secure; discard; HttpOnly=None; version=0 +Set-Cookie3: X-APPLE-WEBAUTH-PCS-Events="\"S2V5QXBwbDoBAAAA8QSiAABatpm4trV8/etQj0u/A6tHpJUw4moCXsjVZDJXsYq6kA==\""; path="/"; domain=.icloud.com; path_spec; domain_dot; secure; expires="2026-05-29 16:06:09Z"; HttpOnly=None; version=0 +Set-Cookie3: X-APPLE-WEBAUTH-PCS-Documents="\"S2V5QXBwbDoBAAAAAgSiAACYRyWWhc7fclX72+yhSwP7V59ZVhDjbD3/73X0+tbM9g==\""; path="/"; domain=.icloud.com; path_spec; domain_dot; secure; expires="2026-05-29 16:06:09Z"; HttpOnly=None; version=0 +Set-Cookie3: X-APPLE-WEBAUTH-PCS-Photos="\"S2V5QXBwbDoBAAAAAwSiAACHdvS2WQTlY3AwSrlOI6jwNVxtl5PqGxlyIwB3aLx51A==\""; path="/"; domain=.icloud.com; path_spec; domain_dot; secure; expires="2026-05-29 16:06:09Z"; HttpOnly=None; version=0 +Set-Cookie3: X-APPLE-WEBAUTH-PCS-Cloudkit="\"S2V5QXBwbDoBAAAABASiAAAP9q4i2ZIdylYNYlXx8nBxmKXR8gNPHT9SP2roM5mYqQ==\""; path="/"; domain=.icloud.com; path_spec; domain_dot; secure; expires="2026-05-29 16:06:09Z"; HttpOnly=None; version=0 +Set-Cookie3: X-APPLE-WEBAUTH-PCS-Safari="\"S2V5QXBwbDoBAAAAFgSiAACPOMgOztdO9qPNcfjmAEma8Qe6YoZUGyYFAMNAUgLOOg==\""; path="/"; domain=.icloud.com; path_spec; domain_dot; secure; expires="2026-05-29 16:06:09Z"; HttpOnly=None; version=0 +Set-Cookie3: X-APPLE-WEBAUTH-PCS-Mail="\"S2V5QXBwbDoBAAAABwSiAACrlC0iGK9bSx5JbJ0D4eW9I9IBOUZZIITLVpXQ8sBmnA==\""; path="/"; domain=.icloud.com; path_spec; domain_dot; secure; expires="2026-05-29 16:06:09Z"; HttpOnly=None; version=0 +Set-Cookie3: X-APPLE-WEBAUTH-PCS-Notes="\"S2V5QXBwbDoBAAAACQSiAAANah46BoeEOKAQozY+h/bkxj7PoDKmNU+m43Tpj9T8NA==\""; path="/"; domain=.icloud.com; path_spec; domain_dot; secure; expires="2026-05-29 16:06:09Z"; HttpOnly=None; version=0 +Set-Cookie3: X-APPLE-WEBAUTH-PCS-News="\"S2V5QXBwbDoBAAAACwSiAACWD0i2SZ/V8tcRZctrfyzmp86gP+tmGX+L4/zPdI10qQ==\""; path="/"; domain=.icloud.com; path_spec; domain_dot; secure; expires="2026-05-29 16:06:09Z"; HttpOnly=None; version=0 +Set-Cookie3: X-APPLE-WEBAUTH-PCS-Sharing="\"S2V5QXBwbDoBAAAADASiAAB4PKdY80kDHNy139gec9nGrrIC1uUmtMpeXly3YS463g==\""; path="/"; domain=.icloud.com; path_spec; domain_dot; secure; expires="2026-05-29 16:06:09Z"; HttpOnly=None; version=0 +Set-Cookie3: X-APPLE-WEBAUTH-TOKEN="\"v=2:t=BA==BST_IAAAAAAABLwIAAAAAGnyPZERDmdzLmljbG91ZC5hdXRovQBRQwz2gEQUeMSQmoFWfYWYe-B6ednKfbyuYcl7f6yIxQEMhsu8dsKNsh3DkrsIyUQsTnE-JxBaAXFpRK9BHtN7_4gW5LtreKPam3-zPLzyYO30KMk3RJfRWefeq2Gore-5VAyynFkd8C-umulnmR6JbAxamQ~~\""; path="/"; domain=.icloud.com; path_spec; domain_dot; secure; expires="2026-05-13 17:19:13Z"; HttpOnly=None; version=0 +Set-Cookie3: X-APPLE-WEBAUTH-FMIP="\"BA==BST_IAAAAAAABLwIAAAAAGnyPZERDmdzLmljbG91ZC5hdXRovQBRQwz2gEQUeMSQmoFWfYWYe-B6ednKfbyuYcl7f6yIxQEMhsu8dsKNsh3DkrsIyUQsTnE-JxBaAXFpRK9BHtN7_4gW5LtreKPam3-zPLzyYLPMTUwpmOKu595hl4PeJtmR5EVt5ZKANCXsjBRmlvCwXIUhFw~~\""; path="/"; domain=.icloud.com; path_spec; domain_dot; secure; discard; HttpOnly=None; version=0 +Set-Cookie3: xr_3n2093n1a=73p69RLLLRMyqW9DQrVFv8skkXX2Jkkf6hOctf+2G9sk; path="/"; domain=p144-fmipweb.icloud.com; path_spec; secure; discard; HttpOnly=None; version=0 diff --git a/cookies/willbrunogmailcom.session b/cookies/willbrunogmailcom.session index ee7328e..782ae66 100644 --- a/cookies/willbrunogmailcom.session +++ b/cookies/willbrunogmailcom.session @@ -1 +1 @@ -{"client_id": "a803c3ce-2586-11f1-a724-8f6777a1d2b5", "session_id": "97997103CCD7FEC9173190AED7457252EBCD7B770AB7B784C902761FC601C83B02A28C2DE1B84D51A690620FBBE43A9F53E20534400A5BABA174C06BCDF6D1239746712B62A97006E8A95F03A96A584A7185B1EB24404B0F03A152E9F46C23451139DEBF74FACF2C476512DC59E85823694E20CF535BBE50", "auth_attributes": "FhGAEYBRc1+aEJafKEWyMXwiTKgOCf4ENrADIEy/mfp/TywQkHi2sHOKpvo4RqEGn1nUCPCD/nfX9Gyi4W0N6XDtZ7HOCNGtlVhaSGJYoWSNk4/5dBcodUuA2hlYQdPs7P2MqVEIotktBhNmd/YYTGPmgjAd7gyRHhAQqC+07dw9Fwqtvv8q0dazx35kIyuErdWQ5Shb8dZ4GRjO59OCjqlwyfjWjvG4OX1pLDHwVHkljxlRfeGLRR/ILOwIwWQY0/8QvHoyFuN8d3qaDFceABK2qXKADwU=", "scnt": "AAAA-jk3OTk3MTAzQ0NEN0ZFQzkxNzMxOTBBRUQ3NDU3MjUyRUJDRDdCNzcwQUI3Qjc4NEM5MDI3NjFGQzYwMUM4M0IwMkEyOEMyREUxQjg0RDUxQTY5MDYyMEZCQkU0M0E5RjUzRTIwNTM0NDAwQTVCQUJBMTc0QzA2QkNERjZEMTIzOTc0NjcxMkI2MkE5NzAwNkU4QTk1RjAzQTk2QTU4NEE3MTg1QjFFQjI0NDA0QjBGMDNBMTUyRTlGNDZDMjM0NTExMzlERUJGNzRGQUNGMkM0NzY1MTJEQzU5RTg1ODIzNjk0RTIwQ0Y1MzVCQkU1MHwzAAABnbFDT1gK_eXTVA7MXRwWGzc7EYk78w8VdprXZA2_PjYhD7pR3jUfI2JNzgoAABK2qWyRXF7vCiS5BW4XleIhsTtwY-WrzQDbwxWdrOD8PmGOC4IDBA", "account_country": "USA", "session_token": "L5N1qDC1TDTKZcGkEcC0YgEUG63qGf9QDs7tuISwtYdNAYqz9ErHPJL3bmQIqs8+2xAQiPTOaceoglSsjq8BThr/OpJBQPFncwAcE2c66T+rK712+3GWgraF5K8yZl2vnXxFY3nLpDYAIz+jt5jiMNxgD9sOugH32kGlal2QBJSRiXnz7SrWe8hI35zfXmjrM/ARD45ZNzuSfYJZ+G6g4bK7+EWqwC3TOhrIpVXzGrqpm7FWgj2W/ZZnNGfpVq+fZ7CZ1Yp0HkEgEiM4WA8+ewstJzGOzh7pVTSc/aTA0l5/8jwqJjEvdc7C+WaJN4tjydlRre+Z6jnWuHcHP0TzhXyKfU3oHKiKMMll1WEJfNFGXzBJyhC2ZgkNMte+Ddr3u/68iv2T5foIsoJv8B8ztcD8ka/lcnf8oP5myT1CYt0P8NlOn3kg9PKWjQR5GbzgDOtmnqeHkhTkAdswD5cidKUXCnP534tur4997bYvZY3bgt6kR7ix4v9F8gBzWkDeUyP7gu0IeYisyDA8Xf1d4C6HdP+65YRoXn/Xqo94+n0A5g19Y+p5pb6X2vE2obKewTZCmH0d+VMMvFECTs9tr37zkYDV2sjXv7oSOTzdT9AWp3zVkL12+IoqswhppcZ+xWBnA2+VX4n83EKf8enRimYFx2gssnSbGJCRBIlkSggoXTO15+5j2l4eO3akjA9d4hDfL+agH/RT/h1oTm08ImD6Vw0lRkOUhFZydUUMgcbt15ZFzBt9bly+rN4BbmM2X7SStGYLRZXxPNe3iu6oy/tTucWeRXjCAHkAWqqrpIfGF/adhaDbRAwaRyfw61YxQM8P/yJy1vXXov3lnyFM9yJiggZrc1DSov7PMfBdhhpFTcAvuiEimP7Utou6b1BjfvyA/nrXqBiCDc6lkHkEd4ozamIMsyM77ZOBsb1fyrNZ867pbubUdqtr/70OuyQkkmVUgRSpJ2N+o7pvL1FY7Ux3Ukh7RNF/O+jATX6XdWBdEi8HF0C0+sHCCQxXAqgIMwDKeqwIQUD3im2i4c7aFQPwIAAStqlygRYH", "trust_eligible": "true", "grant_code": "c7f4eb1fa9c0c4821bb56e7f0d86f4410.0.srzwz.Qg-aHawHsScPT5s8mVqKoA", "trust_token": "HSARMTKNSRVXWFlajR2ecD1662phQjqU9vXxnL49ZjypuVYYXHDpA3wTiX6Mf2J4WDlIhZj52z81aDOuz+VC80bVhV41TSNN4ggoPjW8WnsQrjniTQYkgJycPQNnzhkK4hfe2AMrr/bhrJJm8sHHc+Oh1HUckN6T7T4c1bmf2Qg9tRwsdRDNyMMyFH/Ml/cQlWKj39/YHlY=SRVX"} \ No newline at end of file +{"client_id": "a803c3ce-2586-11f1-a724-8f6777a1d2b5", "session_id": "3C2D0B45AFDCBAC81490E66E2DB79DD28298FB98A4E44381F64D4CFC4A677C6E4BE90E2B7F77BAFC992186F745E8A39EC5B52EE814BB65F1BA8137C80C973C9B657E1300A0E9C22BE32927B428866415AE2E3E66BA4541A67D8411C808E20F8797B807AEB5BDEDA05F2B6FF1306E59D4212F589D7028ED1B", "auth_attributes": "VsXLJh/Xck+NoyZTEUSuCMIuwFZpPHTgWKmVRrIPf4pLGNC52y5WlHKP/lS77U6ULEEAAyIkdNvXrU3uIZr29W7OgGfVgsX+jPkqIb6Ve9v/PGYUAWcvxNMdQD0iHiAZ+Rum9P+QLERwoC3/p7rPhK7NJ94aMlMK/Dg9D+8friEd9nGVgbs7Jy29l5Iir3jWaYsoQKHcFA6D88WCiYEKYp4OfVDog3LEL5IvyYv4uRUAdb2lGOKxcKi4G7iX00T1z+GWb1DGMebu1Ya9+gl9ABTMu8/ZLxM=", "scnt": "AAAA-jNDMkQwQjQ1QUZEQ0JBQzgxNDkwRTY2RTJEQjc5REQyODI5OEZCOThBNEU0NDM4MUY2NEQ0Q0ZDNEE2NzdDNkU0QkU5MEUyQjdGNzdCQUZDOTkyMTg2Rjc0NUU4QTM5RUM1QjUyRUU4MTRCQjY1RjFCQTgxMzdDODBDOTczQzlCNjU3RTEzMDBBMEU5QzIyQkUzMjkyN0I0Mjg4NjY0MTVBRTJFM0U2NkJBNDU0MUE2N0Q4NDExQzgwOEUyMEY4Nzk3QjgwN0FFQjVCREVEQTA1RjJCNkZGMTMwNkU1OUQ0MjEyRjU4OUQ3MDI4RUQxQnwzAAABndoLS0dWpQExE5EJSwL6PIMmSS-olE_EI2BaYpY9v1wSg3Bw60qrXHGB2DoYABTMu8qXOh9L73-Oy0-NxNuGj6itTdeX-GICGK70IWc1gQU98HXS5g", "account_country": "USA", "session_token": "JnRudepNo3OB68SHldgrFYDze+Jxhyll/djlkEG8RCVYTG92cOQBVg26vNvFp86vwz30N2UzJD9hpJMONB4YC3/IxpnIu+J7cLgv3hO2tg98L3vTmdwkUerzeO6cmRnourDqbDNiGGvQhhrtNpzOH4dMeVqy6qjRKZHTVnYEUl8EnT7S/LUHtrXkjgW7cYY3dhbk5xm6J+zVi7oTNzsQ+QQF1Bgr2s7mnr6u0cWeVh7BNIOLfQhyGMlRRYWiG+QjzcJBNlMVWsHEYKLxbVStnE9l2DXcyMhbWy6y8kgdDqINIOyIT9PLtoY3LESDyXKd8fuv32ZYF/qe6P1jKjSZhjSRz+4ZGEBFaPvKQ6qty5CQn62lU6ZZlksR/6KWPNgZQkQJnnmou9fun0xslOjJYCT8EvT1EL7Y0xFQbvgZZTm+1kvqNlPKVtE6gHVhdeJiFZgX8wkZkT5rRx7rTnNFWJVLDjNV2w3zV8lOgiURgrJCwvOQmOl3BiveoDXPPrQlz07RW5l1bDedyMa6puuEPdU2BRWDJLMZmRTnbvnp8IOwcKGNvIQWTnSnViItsdBvJx8HCcLOhI/xBhzJyUxWimSJy2HbQ+Y4DbCniVfjw/ynWKqvM9ntA3TchDS3oiO8l9GJbJ/PhcAgtFVXRmHHD1imHf8OSDIoLp5UDdRi2dw4Z6crZgJNx9Nkp2i3gcv4Zy/vwZHgabi2W2zCU6x9hMP/biDPUBa9fXplH2rMHZ4mRQvKgLQAEYJKQ103754KEExUYNihOnwz5wZGhJAFGCCIuyCD3/I/OLUf48brVbrmuF3ehUY7b7FykIGBLmSRxwCtQr/wxXPhYb3yJ5gygy45+fA3+fXhQ8+W7RlTFduRP5nCHw5vbrMiPhLNpe9Tu3rBT6BTboufzGEmgyZHRwh5c0g/3pfagVAGXtqTONuWY15T5Bmgdz7AKi8JFYPJL84yF2QyZFLwOf05jrjx6f/MvrC4/nX2TlXhr9woxeM6WSmg/fpxizJQT0ybLM5sxxeyVgG3n4BDFONobc+sZa436QAUzLvP2t8m", "trust_eligible": "true", "grant_code": "c7f4eb1fa9c0c4821bb56e7f0d86f4410.0.srzwz.Qg-aHawHsScPT5s8mVqKoA", "trust_token": "HSARMTKNSRVXWFlajR2ecD1662phQjqU9vXxnL49ZjypuVYYXHDpA3wTiX6Mf2J4WDlIhZj52z81aDOuz+VC80bVhV41TSNN4ggoPjW8WnsQrjniTQYkgJycPQNnzhkK4hfe2AMrr/bhrJJm8sHHc+Oh1HUckN6T7T4c1bmf2Qg9tRwsdRDNyMMyFH/Ml/cQlWKj39/YHlY=SRVX"} \ No newline at end of file diff --git a/geocache.db b/geocache.db index ad9b4e270ebd4b945ad6566ca05246638b0ec1c4..3ddbc833f66bfd2db5357f24690d7d56bc4fc7be 100644 GIT binary patch literal 208896 zcmeHw349&rRqu@UU0G}=&eB{f`yyxdC25*ivSTN)97l5OI&B)Rq_K75t2@eFY^!dP z&bSLLEl?n34-|Df*`2)x+M7O z#{YKVi~ke(|5^QiagUvE-ZG2}I!133Mvsr)Hu5_ozq9)F#ZL+Z3IqxS3IqxS3IqxS z3IqxS3IqxS3IqxS)*FGlyLzs8_*PM<)aISjji;&zo1ZARnlAnCC#vpTxmj^*Pt29) z7Mv&K49okbmv}>!% zJ8fCgjXTCob*E*^vT|l@!EH61Cu*(5S*JdBS7}U^^|3ojV|BMYPyTbVTwku1cAa!; zEr+bnRhr9m9sgT$kCl$PwG&RgL4V}7YV3zcoJJFGsL^!lrAfAmUu`tY01Nj#;GDwm z)lZOLdSK>ZRW^)qWxRT_s*#^QIx~LYDEZNni@Uh<^jBobl<4Q0Be$#5kML*>;Ln$4 z$Zew!P+xw6|5B?l_O!pnf3RDAU2po?~~K&_44)EJ3bDiA3x(K0U%X-) z5;F#>ZdmDOSFHGZCu&{V?VNOLm2&Lur_|#9s^c_I5gmchtTY%?M1f0(oq7$%mHhm? zS`A%S!auSWtFhg`A0S;yLDFqqry!ZOtQ%>NY%>nhzH+VM)=K-!HEI`9;7pa5s?KWQ z5X(62!gN-v%&MGMa4bp70}ixj57!>cG!&CbkfrF_nb1ZYhJl!L>&jp{2y~f{-XFtNs zrlK;zuyn;R(}JNIiLI19)O6(}cExG3y=G{~1>8>az58eUNj(26g6Ef2_U=vFhUHv! ze@H38{z`4mtup=JXbwfUKLG?P1OdGFz%*DkAV^DqBH1>1%^aB{&Mb9`B7dqKR6)C(Y! zd2YqaUq=vfy?%i3vKRbzF$BRGQ7>r3c`5{?28*02owku2owku z2owku2owku2owku2owku2owku2owku2owku2owku2owku2owku2owku2owku2owku z2owku2owku2owku2owku2owku2owku2owku2owku2owku2owku2owku2owku2owku z2owku2owku2owku2owku2owku2owku2owku2owku2owku2owku2owku2owku2owku z2owku2owku2owku2owku2owku2owku2owku2owku2owku2owku2owku2owku2owku z2owku2owku2owku2owku2owku2owku2owku2owku2owku2owku2owku2owku2owku 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 diff --git a/src/pymd3_vue_location_sim/geo_cache.py b/src/pymd3_vue_location_sim/geo_cache.py index 1a3d593..d0f53a2 100644 --- a/src/pymd3_vue_location_sim/geo_cache.py +++ b/src/pymd3_vue_location_sim/geo_cache.py @@ -6,8 +6,19 @@ from geopy.adapters import AioHTTPAdapter from geopy.extra.rate_limiter import AsyncRateLimiter logger = logging.getLogger("ios-api") -CACHE_LOOKUP_SQL = "SELECT address FROM location_cache WHERE lat_lon = ?" -CACHE_UPSERT_SQL = "INSERT OR REPLACE INTO location_cache VALUES (?, ?)" +CACHE_LOOKUP_SQL = "SELECT address, favorite FROM location_cache WHERE lat_lon = ?" +CACHE_UPSERT_SQL = """ +INSERT INTO location_cache (lat_lon, address) +VALUES (?, ?) +ON CONFLICT(lat_lon) DO UPDATE SET address = excluded.address +""" +FAVORITE_LOOKUP_SQL = "SELECT favorite FROM location_cache WHERE favorite IS NOT NULL" +FAVORITE_UPSERT_SQL = """ +INSERT INTO location_cache (lat_lon, favorite) +VALUES (?, ?) +ON CONFLICT(lat_lon) DO UPDATE SET favorite = excluded.favorite +""" +FAVORITE_CLEAR_SQL = "UPDATE location_cache SET favorite = NULL WHERE lat_lon = ?" class AsyncReverseGeocoder: @@ -27,9 +38,15 @@ class AsyncReverseGeocoder: cursor.execute(''' CREATE TABLE IF NOT EXISTS location_cache ( lat_lon TEXT PRIMARY KEY, - address TEXT + address TEXT, + favorite TEXT + ) ''') + cursor.execute("PRAGMA table_info(location_cache)") + columns = {row[1] for row in cursor.fetchall()} + if "favorite" not in columns: + cursor.execute("ALTER TABLE location_cache ADD COLUMN favorite TEXT") conn.commit() @staticmethod @@ -40,19 +57,65 @@ class AsyncReverseGeocoder: with sqlite3.connect(self.db_path) as conn: cursor = conn.execute(CACHE_LOOKUP_SQL, (key,)) row = cursor.fetchone() - return json.loads(row[0]) if row else None + cached = {} + if row: + cached['address'] = json.loads(row[0]) if row[0] else {} + cached['favorite'] = json.loads(row[1]) if row[1] else {} + return cached if row else None def _store_cached_address(self, key: str, address_data: dict) -> None: with sqlite3.connect(self.db_path) as conn: conn.execute(CACHE_UPSERT_SQL, (key, json.dumps(address_data))) conn.commit() + def _read_favorites(self) -> list | None: + with sqlite3.connect(self.db_path) as conn: + cursor = conn.execute(FAVORITE_LOOKUP_SQL) + rows = cursor.fetchall() + favorites = [json.loads(row[0]) for row in rows if row[0]] + return favorites if favorites else None + + async def clear_favorite(self, lat: float, lon: float) -> bool: + key = self._cache_key(lat, lon) + cached = self._read_cached_address(key) + if cached and cached.get("favorite"): + favorite = cached.get("favorite") + name = favorite.get("name") if isinstance(favorite, dict) else key + logger.info("Clearing favorite %s", name) + with sqlite3.connect(self.db_path) as conn: + cursor = conn.execute(FAVORITE_CLEAR_SQL, (key,)) + conn.commit() + return cursor.rowcount > 0 + else: + return False + + async def set_favorite(self, lat: float, lon: float, favorite_data: dict) -> bool: + key = self._cache_key(lat, lon) + name = favorite_data.get("name") + if not name: + return False + logger.info("Setting favorite location %s to location_cache for %s", name, key) + try: + with sqlite3.connect(self.db_path) as conn: + conn.execute(FAVORITE_UPSERT_SQL, (key, json.dumps(favorite_data))) + conn.commit() + return True + except sqlite3.Error as e: + logger.exception("Failed to set favorite location %s to location_cache for %s: %s", name, key, e) + return False + + async def get_favorites(self) -> list | None: + """Reverse geocode with SQLite cache.""" + logger.info("Checking location_cache for favorites") + favorites = self._read_favorites() + return favorites + async def get_address(self, lat: float, lon: float) -> dict | None: """Reverse geocode with SQLite cache.""" key = self._cache_key(lat, lon) - logger.info("Checking location_cache for %s", key) cached_address = self._read_cached_address(key) if cached_address is not None: + logger.info("Found cached address for %s", key) return cached_address async with Nominatim( @@ -64,10 +127,11 @@ class AsyncReverseGeocoder: geolocator.reverse, min_delay_seconds=1) location = await reverse(key) if location: + response = {} logger.info("Nominatim response: %s", location) - address_data = location.raw.get("address", {}) - self._store_cached_address(key, address_data) - return address_data + response['address'] = location.raw.get("address", {}) + self._store_cached_address(key, response['address']) + return response return None except Exception: logger.exception("Reverse geocoding failed for key=%s", key) diff --git a/src/pymd3_vue_location_sim/server.py b/src/pymd3_vue_location_sim/server.py index c18f154..7c047df 100644 --- a/src/pymd3_vue_location_sim/server.py +++ b/src/pymd3_vue_location_sim/server.py @@ -642,10 +642,8 @@ class TunneldRunnerSio: "command": "start", "message": "Simulation started", "data": { - - "simulation_active": self.context.simulation_active, - "simulation_queue_state": self.context.simulation_queue_state - } + "simulation_queue": get_simulation_status(), + }, } else: data = { @@ -654,9 +652,8 @@ class TunneldRunnerSio: "command": "start", "message": "Simulation already running", "data": { - "simulation_active": self.context.simulation_active, - "simulation_queue_state": self.context.simulation_queue_state - } + "simulation_queue": get_simulation_status(), + }, } return data @@ -763,6 +760,7 @@ class TunneldRunnerSio: { "type": "simulation_crash", "udid": self.context.udid, + "udid": self.context.udid, "error": traceback.format_exc(), }, namespace="/", @@ -885,7 +883,6 @@ class TunneldRunnerSio: "command": "delete", "message": f"Location {loc_id} deleted from the queue", "data": { - "simulation_queue": get_simulation_status(), "simulation_queue": get_simulation_status(), "location_item": self.context.simulation_queue_data[loc_id], }, @@ -1179,12 +1176,69 @@ class TunneldRunnerSio: else getattr(data, "longitude", 999) ) if latitude != 999 and longitude != 999: - coords = f"{latitude}, {longitude}" rev_geocode = await self.context.reverse_geocode.get_address(latitude, longitude) return rev_geocode else: return None + async def get_favorites(): + favorites = await self.context.reverse_geocode.get_favorites() + return favorites + + async def clear_favorite(data): + latitude = float( + data.get("latitude", 999) + if isinstance(data, dict) + else getattr(data, "latitude", 999) + ) + longitude = float( + data.get("longitude", 999) + if isinstance(data, dict) + else getattr(data, "longitude", 999) + ) + if latitude != 999 and longitude != 999: + clear_status = await self.context.reverse_geocode.clear_favorite(latitude, longitude) + if clear_status: + return "OK", "Favorite cleared" + else: + return "ERROR", "Failed to clear favorite" + else: + return "ERROR", "Invalid latitude and longitude" + + async def set_favorite(data): + favorite = ( + data.get("favorite") + if isinstance(data, dict) + else getattr(data, "favorite", None) + ) + if favorite is not None: + name = ( + favorite.get("name") + if isinstance(favorite, dict) + else getattr(favorite, "name", None) + ) + logger.info("Adding favorite: %s", name) + latitude = float( + favorite.get("latitude", 999) + if isinstance(favorite, dict) + else getattr(favorite, "latitude", 999) + ) + longitude = float( + favorite.get("longitude", 999) + if isinstance(favorite, dict) + else getattr(favorite, "longitude", 999) + ) + if latitude != 999 and longitude != 999 and favorite: + set_status = await self.context.reverse_geocode.set_favorite(latitude, longitude, favorite) + if set_status: + return "OK", "Favorite added" + else: + return "ERROR", "Failed to add favorite" + else: + return "ERROR", "Invalid latitude and longitude" + else: + return "ERROR", "Invalid favorite data" + """ FastAPI HTTP Functions""" def generate_http_response( @@ -1738,6 +1792,20 @@ class TunneldRunnerSio: } return resp + case "reset": + """ Reset the simulation queue""" + reset_queue() + resp = { + "command": command, + "command_class": "simulation_control", + "command_status": "OK", + "message": "Simulation queue reset", + "data": { + "simulation_queue": get_simulation_status(), + } + } + return resp + case "pause": """ Pause the simulation queue""" await pause_simulation_queue() @@ -1751,6 +1819,7 @@ class TunneldRunnerSio: } } return resp + case "resume": """ Resume the simulation queue""" await resume_simulation_queue() @@ -1764,6 +1833,7 @@ class TunneldRunnerSio: } } return resp + case "end": """ End the simulation queue""" logger.info( @@ -1779,12 +1849,14 @@ class TunneldRunnerSio: } } return resp + case "start": """ Start the simulation queue""" logger.info( "Start location simulation request from %s", sid) data = await start_simulation_queue() return data + case "gps-noise": """ Toggle GPS noise""" before_toggle = self.context.simulation_noise @@ -1952,6 +2024,27 @@ class TunneldRunnerSio: "command_status": "ERROR", "message": f"Error starting tunneld: {e}", } + case "restart": + """Restart Tunneld""" + logger.info("Restart tunneld request from %s: %s", sid, data) + try: + self._tunneld_core.clear() + await asyncio.sleep(2) + self._tunneld_core.start() + return { + "command_status": "OK", + "command_class": "tunneld_control", + "command": command, + "message": "Tunneld started successfully", + } + except Exception as e: + logger.error("Error restarting tunneld: %s", e) + return { + "command_status": "ERROR", + "command_class": "tunneld_control", + "command": command, + "message": f"Error starting tunneld: {e}", + } case "start-watcher": """ Start Tunneld Watcher """ @@ -2060,6 +2153,76 @@ class TunneldRunnerSio: rev_geocode = await get_reverse_geocode(data) return rev_geocode + @self.context.sio.event + async def favorite_control(sid, data: dict): + command = ( + data.get("command") + if isinstance(data, dict) + else getattr(data, "command", None) + ) + logger.info( + "Favorite Control command: %s requested from %s", command, sid + ) + match command: + case "set": + """ Add a favorite location to database""" + cstat, cmessage = await set_favorite(data) + if cstat == "ERROR": + logger.error('Favorite set failed: %s', cmessage) + resp = { + "command": command, + "command_class": "favorite_control", + "command_status": cstat, + "message": cmessage, + "data": { + "favorites": await get_favorites(), + } + } + return resp + + case "clear": + """ Clear a favorite location from database""" + cstat, cmessage = await clear_favorite(data) + resp = { + "command": command, + "command_class": "favorite_control", + "command_status": cstat, + "message": cmessage, + "data": { + "favorites": await get_favorites(), + } + } + return resp + + case "get": + """ Get favorite locations from database""" + favs = await get_favorites() + if favs: + cstat = "OK" + cmessage = "Favorites retrieved successfully" + else: + cstat = "ERROR" + cmessage = "No favorites found" + resp = { + "command": command, + "command_class": "favorite_control", + "command_status": cstat, + "message": cmessage, + "data": { + "favorites": favs, + } + } + return resp + + case _: + return { + "command": command, + "command_class": "favorite_control", + "command_status": "ERROR", + "message": f"Invalid command: {command}", + } + + self._vue_app.include_router(self._app, prefix="/api") self._vue_app.mount(