iobroker.google-sharedlocations2 0.3.5 → 0.3.6

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.
package/README.md CHANGED
@@ -27,6 +27,10 @@ Copyright and trademark of Google are property of Google.
27
27
  Placeholder for the next version (at the beginning of the line):
28
28
  ### **WORK IN PROGRESS**
29
29
  -->
30
+ ### 0.3.6 (2026-04-25)
31
+ * (Garfonso) somehow the old improve cookie call does not work anymore (since switch to fetch). Don't see why. -> So we just run the browser once a day.
32
+ * (Garfonso) Login with browser no tries to clear cookies in browser, if normal login does not work.
33
+
30
34
  ### 0.3.5 (2026-04-22)
31
35
  * (Garfonso) resize logo.
32
36
 
@@ -39,35 +43,6 @@ Copyright and trademark of Google are property of Google.
39
43
  ### 0.3.2 (2026-02-09)
40
44
  * (Garfonso) refresh with browser ignores cookies from adapter
41
45
 
42
- ### 0.3.1 (2026-02-09)
43
- * (Garfonso) improved logging during login.
44
- * (Garfonso) handle situation where browser logs in with his cookie, so we only need to read the cookie.
45
-
46
- ### 0.3.0 (2026-02-09)
47
- * (Garfonso) do not update states if no new position is available.
48
- * (Garfonso) fixed: refresh via browser
49
- * (Garfonso) added: force refresh via browser by setting "forceRefresh" state to true
50
- * (Garfonso) changed: now store complete cookies array
51
-
52
- ### 0.2.0 (2026-02-03)
53
- * (Garfonso) now using data directory to store chrome data
54
- * (Garfonso) try to use existing cookie in browser to refresh cookie without login.
55
-
56
- ### 0.1.1 (2026-02-02)
57
- * (Garfonso) improved recovery from login errors
58
-
59
- ### 0.1.0 (2026-02-02)
60
- * (Garfonso) added: support for places
61
- * (Garfonso) added: support for fences
62
- * (Garfonso) try to prevent login as much as possible.
63
-
64
- ### 0.0.3 (2026-01-28)
65
- * (Garfonso) prevent login if no username and password is set
66
- * (Garfonso) fix tests
67
-
68
- ### 0.0.2 (2026-01-28)
69
- * (Garfonso) store password encrypted
70
-
71
46
  ## License
72
47
  MIT License
73
48
 
package/io-package.json CHANGED
@@ -1,8 +1,21 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "google-sharedlocations2",
4
- "version": "0.3.5",
4
+ "version": "0.3.6",
5
5
  "news": {
6
+ "0.3.6": {
7
+ "en": "somehow the old improve cookie call does not work anymore (since switch to fetch). Don't see why. -> So we just run the browser once a day.\nLogin with browser now tries to clear cookies in browser, if normal login does not work.",
8
+ "de": "irgendwie funktioniert der alte Cookie-Verbessern-Aufruf nicht mehr (seit Umschalten auf Fetch). Ich sehen nicht, warum. -> Also starten wir den Browser einmal am Tag.\nEinloggen mit Browser versucht jetzt, Cookies im Browser zu löschen, wenn normale Anmeldung nicht funktioniert.",
9
+ "ru": "как-то старый улучшенный вызов куки больше не работает (поскольку переключается на извлечение). Не понимаю почему. -> Поэтому мы просто запускаем браузер один раз в день.\nЛогин с браузером не пытается очистить файлы cookie в браузере, если обычный логин не работает.",
10
+ "pt": "de alguma forma o velho melhorar chamada de cookies não funciona mais (desde switch to fetch). Não vejo porquê. -> Então, nós apenas dirigimos o navegador uma vez por dia.\nLogin com o navegador não tenta limpar cookies no navegador, se o login normal não funcionar.",
11
+ "nl": "op de een of andere manier werkt de oude verbetering cookie call niet meer (sinds switch to fetch). Ik zie niet in waarom. -> Dus we doen de browser één keer per dag.\nInloggen met browser niet probeert te wissen cookies in de browser, als de normale login niet werkt.",
12
+ "fr": "d'une certaine façon, l'ancien appel à cookies d'amélioration ne fonctionne plus (depuis le commutateur pour récupérer). Je ne vois pas pourquoi. -> Donc, on fait fonctionner le navigateur une fois par jour.\nSe connecter avec le navigateur ne tente pas d'effacer les cookies dans le navigateur, si la connexion normale ne fonctionne pas.",
13
+ "it": "in qualche modo il vecchio migliorare la chiamata dei cookie non funziona più (dal momento che l'interruttore a prendere). Non capisco perche'. - > Quindi facciamo funzionare il browser una volta al giorno.\nAccedi con il browser non cerca di cancellare i cookie nel browser, se il normale login non funziona.",
14
+ "es": "de alguna manera la vieja mejora de la llamada de cookies ya no funciona (después de cambiar a buscar). No veo por qué. - No. Así que sólo corremos el navegador una vez al día.\nIniciar sesión con el navegador no intenta limpiar las cookies en el navegador, si el login normal no funciona.",
15
+ "pl": "jakoś stare ulepszenie cookies połączenia nie działa już (od przełącznika do pobierania). Nie widzę powodu. - > Więc po prostu sprawdzamy przeglądarkę raz dziennie.\nZaloguj się z przeglądarką bez próby wyczyszczenia plików cookie w przeglądarce, jeśli normalne logowanie nie działa.",
16
+ "uk": "якось старий поліпшення cookie-зв'язку не працює більше (з перемикачем на fetch). Не бачте, чому. до Так ми просто запускаємо браузер один раз на добу.\nВвійти з браузером не намагається очистити файли cookie в браузері, якщо звичайний логін не працює.",
17
+ "zh-cn": "不知何故,旧的改进饼干呼叫已不再可行(因为切换到接取). 无明故. - > 开口 所以我们只是每天运行浏览器一次.\n在浏览器中登录不尝试清除 cookie, 如果正常的登录无效 ."
18
+ },
6
19
  "0.3.5": {
7
20
  "en": "resize logo.",
8
21
  "de": "größe des logos angepasst.",
@@ -80,19 +93,6 @@
80
93
  "pl": "nie aktualizować stanów, jeśli nie jest dostępna nowa pozycja.\nstałe: odświeżenie przez przeglądarkę\ndodane: siła odświeżania przez przeglądarkę poprzez ustawienie stanu \"forceRefresh\" na true\nzmienione: teraz przechowywać pełną tablicę cookies",
81
94
  "uk": "не оновлювати стани, якщо немає нової позиції.\nвиправлено: оновлення через браузер\nдодано: сила освіження через браузер за допомогою налаштування \"forceRefresh\" стану true\nзмінено: тепер зберігає повний масив файлів cookie",
82
95
  "zh-cn": "如果没有新职位,则不更新状态.\n固定: 通过浏览器刷新\n添加: 通过浏览器将“ ForceRefresh” 状态设置为真以强制刷新\n更改: 现在存储完整的 cookie 阵列"
83
- },
84
- "0.2.0": {
85
- "en": "now using data directory to store chrome data\ntry to use existing cookie in browser to refresh cookie without login.",
86
- "de": "jetzt mit data directory, um chromdaten zu speichern\nversuchen, existierenden cookie im browser zu verwenden, um cookie ohne anmeldung zu aktualisieren.",
87
- "ru": "теперь используя директор данных для хранения хромированных данных\nпопробуйте использовать существующий cookie в браузере, чтобы обновить cookie без входа в систему.",
88
- "pt": "agora usando o diretor de dados para armazenar dados de cromo\ntentar usar cookie existente no navegador para atualizar cookie sem login.",
89
- "nl": "nu met behulp van data director om chroom gegevens op te slaan\nprobeer bestaande cookie in de browser te gebruiken om cookie te vernieuwen zonder in te loggen.",
90
- "fr": "maintenant en utilisant le directeur de données pour stocker des données chrome\nessayez d'utiliser le cookie existentint dans le navigateur pour rafraîchir le cookie sans vous connecter.",
91
- "it": "ora utilizzando il data director per memorizzare i dati cromati\nprovare a utilizzare cookie esisteint nel browser per aggiornare i cookie senza effettuare il login.",
92
- "es": "ahora utilizando el director de datos para almacenar datos de cromo\ntratar de utilizar la cookie existente en el navegador para refrescar la cookie sin login.",
93
- "pl": "teraz za pomocą dyrektora danych do przechowywania danych chromowych\nspróbuj użyć plików cookie existint w przeglądarce, aby odświeżyć pliki cookie bez logowania.",
94
- "uk": "тепер використовуючи каталог даних для зберігання хромованих даних\nспробуйте використовувати наявний cookie-файли в браузері, щоб оновити cookie без реєстрації.",
95
- "zh-cn": "现在使用数据总监存储铬数据\n尝试在浏览器中使用存在 cookie来刷新 cookie而不登录."
96
96
  }
97
97
  },
98
98
  "titleLang": {
@@ -158,7 +158,7 @@
158
158
  ],
159
159
  "globalDependencies": [
160
160
  {
161
- "admin": ">=7.6.17"
161
+ "admin": ">=7.6.20"
162
162
  }
163
163
  ],
164
164
  "osDependencies": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.google-sharedlocations2",
3
- "version": "0.3.5",
3
+ "version": "0.3.6",
4
4
  "description": "Share your location with iobroker via google maps.",
5
5
  "author": {
6
6
  "name": "Garfonso",
package/src/lib/Cookie.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { GoogleSharedlocations2 } from '../main';
2
2
  import puppeteer from 'puppeteer';
3
3
  import type { Browser, Page, CookieData, CookiePriority, CookieSameSite } from 'puppeteer';
4
- import { mkdir } from 'fs/promises';
4
+ import { mkdir } from 'node:fs/promises';
5
5
  import type { RequestCredentials } from 'undici-types/fetch';
6
6
 
7
7
  /**
@@ -167,10 +167,10 @@ export class Cookie {
167
167
  }
168
168
  const cIndex = this.cookies.findIndex(c => c.name === name);
169
169
  if (cIndex < 0) {
170
- this.log.debug(`Adding new cookie from header: ${cookie.name}=${cookie.value}`);
170
+ this.log.debug(`Adding new cookie from header: ${cookie.name}`);
171
171
  this.cookies.push(cookie); //add
172
172
  } else {
173
- this.log.debug(`Updating cookie from header: ${cookie.name}=${cookie.value}`);
173
+ this.log.debug(`Updating cookie from header: ${cookie.name}`);
174
174
  this.cookies[cIndex] = cookie; //update
175
175
  }
176
176
  }
@@ -194,7 +194,6 @@ export class Cookie {
194
194
  * Improve the current cookie by making a request to Google My Account page.
195
195
  */
196
196
  async improveCookie(): Promise<boolean> {
197
- //see https://github.com/costastf/locationsharinglib/blob/master/locationsharinglib/locationsharinglib.py#L105
198
197
  const url = 'https://myaccount.google.com/?hl=en';
199
198
  const options = {
200
199
  credentials: 'same-origin' as RequestCredentials, //or do we need 'include' here?
@@ -205,10 +204,13 @@ export class Cookie {
205
204
  };
206
205
 
207
206
  try {
207
+ this.log.debug('Trying to improve cookie.');
208
208
  const response = await fetch(url, options);
209
209
 
210
210
  if (response.status !== 200) {
211
- this.log?.error(`Failed improving cookie: ${response.status}`);
211
+ this.log?.error(`Failed improving cookie: ${response.status} - ${response.statusText}`);
212
+ console.log(response.headers);
213
+ console.log(await response.text());
212
214
  return false;
213
215
  }
214
216
  await this.augmentCookieFromHeader(response.headers);
@@ -263,6 +265,7 @@ export class Cookie {
263
265
  }
264
266
 
265
267
  //send request with current cookies
268
+ //see https://github.com/costastf/locationsharinglib/blob/master/locationsharinglib/locationsharinglib.py#L105 for info on parameters
266
269
  this.log.debug('Sending request with current cookies');
267
270
  const url =
268
271
  'https://www.google.com/maps/rpc/locationsharing/read?authuser=2&hl=en&gl=us&pb=!1m7!8m6!1m3!1i14!2i8413!3i5385!2i6!3x4095!2m3!1e0!2sm!3i407105169!3m7!2sen!5e1105!12m4!1e68!2m2!1sset!2sRoadmap!4e1!5m4!1e4!8m2!1e0!1e1!6m9!1e12!2i2!26m1!4b1!30m1!1f1.3953487873077393!39b1!44e1!50e0!23i4111425';
@@ -459,59 +462,62 @@ export class Cookie {
459
462
  this.log.info('Login successful with existing session, no need to fill in credentials.');
460
463
  return true;
461
464
  }
462
- return false;
463
- }
464
-
465
- try {
466
- logDebug('Trying to click on username, if user was logged in before.');
467
- const userElement = await page.$(`[data-email="${this.username}"]`);
468
- if (userElement) {
469
- await userElement.click();
470
- } else {
471
- logDebug('No user element found, filling in username.');
465
+ } else {
466
+ try {
467
+ logDebug('Trying to click on username, if user was logged in before.');
468
+ const userElement = await page.$(`[data-email="${this.username}"]`);
469
+ if (userElement) {
470
+ await userElement.click();
471
+ } else {
472
+ logDebug('No user element found, filling in username.');
473
+ await page.locator('#identifierId').fill(this.username);
474
+ }
475
+ } catch (e: any) {
476
+ logDebug(`Ok, no user it seems (${e}). Let's fill in useranme`);
477
+ logDebug('filling in username.');
472
478
  await page.locator('#identifierId').fill(this.username);
473
479
  }
474
- } catch (e: any) {
475
- logDebug(`Ok, no user it seems (${e}). Let's fill in useranme`);
476
- logDebug('filling in username.');
477
- await page.locator('#identifierId').fill(this.username);
478
- }
479
480
 
480
- //is this enough, or do we need to search button in this div?
481
- logDebug('clicking user next button.');
482
- await page.locator('#identifierNext').click();
483
- //waiting for #password fails in headles.. :-(
484
- logDebug('waiting for network idle before filling password');
485
- await page.waitForNetworkIdle({ idleTime: 2000 });
486
-
487
- logDebug('filling in password.');
488
- //do we need to wait until page is loaded / rendered here?
489
- await page.locator('input[type="password"]').fill(this.password);
490
- logDebug('clicking password next button.');
491
- await page.locator('#passwordNext').click();
492
- //await page.waitForNetworkIdle({ idleTime: 2000 }); -> does never happen in headless.. :-/
493
- logDebug(
494
- 'waiting for page to load after password, currently waiting fixed 3 seconds, because network never gets idle?',
495
- );
496
- await new Promise(resolve => setTimeout(resolve, 3000));
481
+ //is this enough, or do we need to search button in this div?
482
+ logDebug('clicking user next button.');
483
+ await page.locator('#identifierNext').click();
484
+ //waiting for #password fails in headles.. :-(
485
+ logDebug('waiting for network idle before filling password');
486
+ await page.waitForNetworkIdle({ idleTime: 2000 });
487
+
488
+ logDebug('filling in password.');
489
+ //do we need to wait until page is loaded / rendered here?
490
+ await page.locator('input[type="password"]').fill(this.password);
491
+ logDebug('clicking password next button.');
492
+ await page.locator('#passwordNext').click();
493
+ //await page.waitForNetworkIdle({ idleTime: 2000 }); -> does never happen in headless.. :-/
494
+ logDebug(
495
+ 'waiting for page to load after password, currently waiting fixed 3 seconds, because network never gets idle?',
496
+ );
497
+ await new Promise(resolve => setTimeout(resolve, 3000));
497
498
 
498
- logDebug('navigating to google maps to load right cookies.');
499
- await page.goto('https://www.google.com/maps');
500
- logDebug('getting cookies.');
501
- await this.getCookiesFromPage(page);
502
- await this.cleanUp();
503
- const results = await this.sendRequest();
504
- if (results && results.length > 0) {
505
- this.log.info('Login successful with existing session, no need to fill in credentials.');
506
- return true;
499
+ logDebug('navigating to google maps to load right cookies.');
500
+ await page.goto('https://www.google.com/maps');
501
+ logDebug('getting cookies.');
502
+ await this.getCookiesFromPage(page);
503
+ await this.cleanUp();
504
+ const results = await this.sendRequest();
505
+ if (results && results.length > 0) {
506
+ this.log.info('Login successful with existing session, no need to fill in credentials.');
507
+ return true;
508
+ }
507
509
  }
508
- return false;
509
510
  } catch (e) {
510
511
  this.log.error(`Error in puppeteer: ${(e as Error).message}`);
511
512
  this.log.error(`The step puppeteer failed was: ${currentStep}`);
512
513
  // try to close browser if open
513
514
  await this.cleanUp();
514
515
  }
516
+ // ok, somehow everything failed -> see if we can retry:
517
+ if (!forceLogin && this.username && this.password) {
518
+ this.log.info('Retrying to login with user & password.');
519
+ return this.loginToGetNewCookies(true);
520
+ }
515
521
  return false;
516
522
  }
517
523
 
package/src/main.ts CHANGED
@@ -23,6 +23,7 @@ export class GoogleSharedlocations2 extends utils.Adapter {
23
23
  _pollTimeout: ioBroker.Timeout | undefined;
24
24
  _pollInterval: number = 300;
25
25
  _successFullPolls: number = 1; // let us try a relogin at start, if cookie does not work.
26
+ _lastBrowserRefresh = 0;
26
27
  _users: Record<string, User> = {};
27
28
  fences: Fence[] = [];
28
29
  cookie: Cookie;
@@ -67,6 +68,7 @@ export class GoogleSharedlocations2 extends utils.Adapter {
67
68
  if (this._pollInterval > MAX_INT32) {
68
69
  this._pollInterval = MAX_INT32;
69
70
  }
71
+ this.log.info(`Working with pollInterval of ${this._pollInterval}s`);
70
72
 
71
73
  //read fences:
72
74
  for (const fenceConfig of this.config.fences || []) {
@@ -123,10 +125,12 @@ export class GoogleSharedlocations2 extends utils.Adapter {
123
125
  this.log.debug('Polling positions with current cookies.');
124
126
  const lastSuccessPolls = this._successFullPolls;
125
127
  await this.sendRequest();
126
- if (this._successFullPolls > 0 && lastSuccessPolls !== this._successFullPolls) {
127
- if (this._successFullPolls % 10 === 0) {
128
+ if (this._successFullPolls > 0 && lastSuccessPolls < this._successFullPolls) {
129
+ if (Date.now() - this._lastBrowserRefresh > 24 * 60 * 60 * 1000) {
128
130
  //try to get some more headers from google:
129
- await this.cookie.improveCookie();
131
+ //await this.cookie.improveCookie(); -> somehow fails always..?? Don't understand, why.
132
+ await this.cookie.refreshCookieWithBrowser();
133
+ this._lastBrowserRefresh = Date.now();
130
134
  }
131
135
  }
132
136
  }