@chronicle.app/arc-timeline 0.4.0 → 0.5.0
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.
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Extractor, Record } from '@chronicle.app/etl';
|
|
1
|
+
import { Extractor, Record, type Survey, type SurveyOptions } from '@chronicle.app/etl';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import ArcTimelineTransformer from './ArcTimelineTransformer.js';
|
|
4
4
|
export declare class ArcTimelineExtractor extends Extractor<typeof ArcTimelineExtractor> {
|
|
@@ -30,6 +30,12 @@ export declare class ArcTimelineExtractor extends Extractor<typeof ArcTimelineEx
|
|
|
30
30
|
limit?: number | undefined;
|
|
31
31
|
}>;
|
|
32
32
|
extract(): AsyncGenerator<Record>;
|
|
33
|
+
/**
|
|
34
|
+
* The visits and travels a run reads, and when they started, from every
|
|
35
|
+
* day file in range. A survey keeps only each item's id and start, one day
|
|
36
|
+
* at a time, where a run holds every item and then reads trips' samples.
|
|
37
|
+
*/
|
|
38
|
+
survey(options?: SurveyOptions): Promise<Survey>;
|
|
33
39
|
private resolvePerson;
|
|
34
40
|
private loadSamples;
|
|
35
41
|
determineCount(): Promise<number | null>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Extractor } from '@chronicle.app/etl';
|
|
2
|
-
import { buildICloudPersonSchema } from '@chronicle.app/
|
|
1
|
+
import { Extractor, countMonth, } from '@chronicle.app/etl';
|
|
2
|
+
import { buildICloudPersonSchema } from '@chronicle.app/apple';
|
|
3
3
|
import { readFile, readdir } from 'node:fs/promises';
|
|
4
4
|
import { join } from 'node:path';
|
|
5
5
|
import { gunzipSync } from 'node:zlib';
|
|
@@ -119,6 +119,47 @@ export class ArcTimelineExtractor extends Extractor {
|
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
|
+
/**
|
|
123
|
+
* The visits and travels a run reads, and when they started, from every
|
|
124
|
+
* day file in range. A survey keeps only each item's id and start, one day
|
|
125
|
+
* at a time, where a run holds every item and then reads trips' samples.
|
|
126
|
+
*/
|
|
127
|
+
async survey(options = {}) {
|
|
128
|
+
const config = this.config;
|
|
129
|
+
const dir = await this.findDailyDir(config.input);
|
|
130
|
+
const sinceKey = config.since ? dayKey(config.since) : undefined;
|
|
131
|
+
const untilKey = config.until ? dayKey(config.until) : undefined;
|
|
132
|
+
const seen = new Set();
|
|
133
|
+
const visits = { count: 0, ...(options.byMonth && { byMonth: {} }) };
|
|
134
|
+
const travels = { count: 0, ...(options.byMonth && { byMonth: {} }) };
|
|
135
|
+
// Named by day, newest first, so a range skips whole files as a run does.
|
|
136
|
+
for (const { path, key } of await this.listDayFiles(dir)) {
|
|
137
|
+
if (sinceKey && key < sinceKey)
|
|
138
|
+
break;
|
|
139
|
+
if (untilKey && key > untilKey)
|
|
140
|
+
continue;
|
|
141
|
+
for (const item of (await this.readDayFile(path)).items) {
|
|
142
|
+
const { base } = item;
|
|
143
|
+
if (!base || base.deleted || seen.has(base.id))
|
|
144
|
+
continue;
|
|
145
|
+
const start = new Date(base.startDate);
|
|
146
|
+
if ((config.since && start < config.since) || (config.until && start > config.until))
|
|
147
|
+
continue;
|
|
148
|
+
const kind = item.visit || base.isVisit ? visits : item.trip ? travels : undefined;
|
|
149
|
+
if (!kind)
|
|
150
|
+
continue;
|
|
151
|
+
seen.add(base.id);
|
|
152
|
+
kind.count++;
|
|
153
|
+
if (!kind.earliest || start < kind.earliest)
|
|
154
|
+
kind.earliest = start;
|
|
155
|
+
if (!kind.latest || start > kind.latest)
|
|
156
|
+
kind.latest = start;
|
|
157
|
+
if (kind.byMonth)
|
|
158
|
+
countMonth(kind.byMonth, start);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return { visits, travels };
|
|
162
|
+
}
|
|
122
163
|
// The person whose timeline this is: an explicit `--identity` override, else
|
|
123
164
|
// the macOS iCloud account (so Arc data merges onto the same person as other
|
|
124
165
|
// iCloud-sourced data). An override is keyed the same way, so it merges too.
|
|
@@ -47,9 +47,9 @@ export default class ArcTimelineTransformer extends ChronicleTransformer {
|
|
|
47
47
|
};
|
|
48
48
|
const action = {
|
|
49
49
|
'@type': 'TravelAction',
|
|
50
|
-
|
|
50
|
+
// Keyed by the journey it made, which has the timeline item's ID.
|
|
51
|
+
'@key': ['@type', 'source', 'result.sourceId'],
|
|
51
52
|
source: 'arc',
|
|
52
|
-
sourceId: item.base.id,
|
|
53
53
|
agent: person,
|
|
54
54
|
result: journey,
|
|
55
55
|
startTime: new Date(item.base.startDate),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chronicle.app/arc-timeline",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"types": "./dist/index.d.ts",
|
|
6
6
|
"files": [
|
|
@@ -22,9 +22,9 @@
|
|
|
22
22
|
"type": "module",
|
|
23
23
|
"description": "Chronicle plugin for location tracking data from Arc timeline database",
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"@chronicle.app/etl": "0.
|
|
26
|
-
"@chronicle.app/schema": "0.
|
|
27
|
-
"@chronicle.app/tsconfig": "0.
|
|
25
|
+
"@chronicle.app/etl": "0.5.0",
|
|
26
|
+
"@chronicle.app/schema": "0.5.0",
|
|
27
|
+
"@chronicle.app/tsconfig": "0.5.0",
|
|
28
28
|
"@types/node": "^22.10.1",
|
|
29
29
|
"typescript": "^5.7.2"
|
|
30
30
|
},
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"registry": "https://registry.npmjs.org/"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@chronicle.app/
|
|
42
|
+
"@chronicle.app/apple": "0.5.0",
|
|
43
43
|
"zod": "^3.24.1"
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|
|
@@ -66,7 +66,12 @@
|
|
|
66
66
|
"visits",
|
|
67
67
|
"travels"
|
|
68
68
|
],
|
|
69
|
-
"default": true
|
|
69
|
+
"default": true,
|
|
70
|
+
"locations": [
|
|
71
|
+
{
|
|
72
|
+
"path": "~/Library/Mobile Documents/iCloud~com~bigpaua~Arc-Timeline-Editor/Documents/Exports"
|
|
73
|
+
}
|
|
74
|
+
]
|
|
70
75
|
}
|
|
71
76
|
},
|
|
72
77
|
"platforms": [
|