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 +4 -29
- package/io-package.json +15 -15
- package/package.json +1 -1
- package/src/lib/Cookie.ts +53 -47
- package/src/main.ts +7 -3
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.
|
|
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.
|
|
161
|
+
"admin": ">=7.6.20"
|
|
162
162
|
}
|
|
163
163
|
],
|
|
164
164
|
"osDependencies": {
|
package/package.json
CHANGED
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}
|
|
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}
|
|
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
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
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
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
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
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
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
|
|
127
|
-
if (this.
|
|
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
|
}
|