This code snippet processes location history data from Google Takeout and combines it with timeline data from Google Calendar, likely for analysis or visualization purposes. It uses Selenium to scrape timeline data and writes the reconciled data to JSON files.
npm run import -- "reconcile timeline"
var importer = require('../Core');
var {
loadLocations, averageDestinations, reconcileTimelineLocations,
runSeleniumCell
} = importer.import("load locations export data",
"average latitude longitude",
"reconcile timeline calendar",
"selenium cell")
var PROFILE_PATH = process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE;
var PROJECT_PATH = PROFILE_PATH + '/Collections/timeline';
var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
if(typeof geoLocations === 'undefined') {
var geoLocations, readTimelinePage, getGoogleTimeline;
}
function loadOnce() {
console.log('loading location history. this may take a while');
if(typeof geoLocations !== 'undefined') {
return Promise.resolve(geoLocations);
}
geoLocations = loadLocations('/Users/briancullinan/Downloads/Takeout 7/Location History/Location History.json');
return runSeleniumCell([
'log in google',
'single timeline page',
'scrape google timeline'
])
.then(r => {
readTimelinePage = r.readTimelinePage;
getGoogleTimeline = r.getGoogleTimeline;
return geoLocations;
})
}
function reconcileTimeline(date) {
var dateKey = date.getDate() + months[date.getMonth()]
+ (date.getFullYear() + '').substr(2, 2);
return loadOnce()
.then(() => getGoogleTimeline(date))
.then(() => readTimelinePage())
.catch(e => console.log(e))
.then(timelineLocations => {
if (timelineLocations.length === 0) {
console.log('no timeline data for ' + date);
return;
}
var dateKey = timelineLocations[0].timeline;
fs.writeFileSync(
PROJECT_PATH + '/timeline-' + dateKey + '.json',
JSON.stringify(timelineLocations, null, 4))
if (typeof geoLocations[dateKey] === 'undefined') {
console.log('no location data for ' + date);
return;
}
var d = averageDestinations(geoLocations[dateKey], timelineLocations);
if (d.length === 0) {
console.log('no still geo data for ' + date);
return;
}
fs.writeFileSync(
PROJECT_PATH + '/location-' + dateKey + '.json',
JSON.stringify(d, null, 4))
return reconcileTimelineLocations(d, date);
})
.then(events => {
fs.writeFileSync(
PROJECT_PATH + '/events-' + dateKey + '.json',
JSON.stringify(events, null, 4));
return events;
})
.catch(e => console.log(e))
}
module.exports = reconcileTimeline;
function daysInMonth(month,year) {
return new Date(year, month, 0).getDate();
}
if(typeof $ !== 'undefined') {
$.async();
var start = new Date('10/1/2016');
var end = daysInMonth(start.getMonth()+1, start.getFullYear());
var promises = [];
for(var day = start.getDate(); day <= end; day++) {
var tmpDate = new Date(start);
tmpDate.setDate(day);
promises.push((date => resolve => reconcileTimeline(date)
.catch(e => console.log(e))
.then(r => resolve(r)))(tmpDate));
}
importer.runAllPromises(promises)
.then(r => $.sendResult(r))
.catch(e => $.sendError(e))
}
const importer = require('../Core');
const {
loadLocations,
averageDestinations,
reconcileTimelineLocations,
runSeleniumCell
} = importer.import([
'load locations export data',
'average latitude longitude',
'reconcile timeline calendar',
'selenium cell'
]);
const { fs } = require('fs');
const { join } = require('path');
const { format } = require('date-fns');
const { parse } = require('date-fns');
const PROFILE_PATH = process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE;
const PROJECT_PATH = join(PROFILE_PATH, 'Collections/timeline');
const months = [
'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec'
];
// TODO: Extract daysInMonth function to date-utils.js file
function daysInMonth(month, year) {
return parse(`$ {
year}-${month}-01`, `yyyy-MM-dd`, new Date()).getDate() - 1;
}
class Timeline {
constructor() {
this.geoLocations = {};
}
loadTimeline(date) {
const dateKey = format(date, `yyyy-MM`);
if (this.geoLocations[dateKey]) {
return Promise.resolve(this.geoLocations[dateKey]);
}
console.log(`Loading locations for ${dateKey}...`);
return runSeleniumCell([
'log in google',
'single timeline page',
'scrape google timeline'
])
.then((r) => {
this.readTimelinePage = r.readTimelinePage;
this.getGoogleTimeline = r.getGoogleTimeline;
return this.geoLocations[dateKey] = loadLocations(`/Users/briancullinan/Downloads/Takeout 7/Location History/Location History.json`);
});
}
reconcileTimeline(date) {
const dateKey = format(date, `yyyy-MM`);
return this.loadTimeline(date)
.then(() => this.getGoogleTimeline(date))
.then(() => this.readTimelinePage())
.then((timelineLocations) => {
if (timelineLocations.length === 0) {
console.log(`No timeline data for ${dateKey}`);
return;
}
const d = averageDestinations(this.geoLocations[dateKey], timelineLocations);
if (d.length === 0) {
console.log(`No still geo data for ${dateKey}`);
return;
}
return reconcileTimelineLocations(d, date);
})
.then((events) => {
fs.writeFileSync(
join(PROJECT_PATH, `events-${dateKey}.json`),
JSON.stringify(events, null, 4)
);
return events;
})
.catch((e) => console.log(e));
}
}
const timeline = new Timeline();
function reconcileTimelineCell(date) {
return timeline.reconcileTimeline(date);
}
module.exports = reconcileTimelineCell;
if (typeof $!== 'undefined') {
$.async();
const start = new Date('10/1/2016');
const end = daysInMonth(start.getMonth() + 1, start.getFullYear());
const promises = [];
for (let day = start.getDate(); day <= end; day++) {
const tmpDate = new Date(start);
tmpDate.setDate(day);
promises.push((date => resolve => timeline.reconcileTimeline(date)
.catch(e => console.log(e))
.then(r => resolve(r)))(tmpDate));
}
importer.runAllPromises(promises)
.then(r => $.sendResult(r))
.catch(e => $.sendError(e));
}
This code snippet appears to be part of a larger script designed to analyze location history data from Google Takeout and reconcile it with timeline data from Google Calendar.
Here's a breakdown:
Dependencies:
importer
: A custom module likely containing functions for interacting with various data sources and tools.Importing Functions:
importer
:
loadLocations
: Loads location history data from a JSON file.averageDestinations
: Calculates average latitude and longitude from a set of locations.reconcileTimelineLocations
: Reconciles timeline data with location history.runSeleniumCell
: Executes a Selenium script (likely for web scraping).Configuration:
Global Variables:
geoLocations
(location history data) and other variables, potentially initialized later.loadOnce
Function:
reconcileTimeline
Function:
loadOnce
to ensure location history and timeline data are loaded.