Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SyncDelay #372

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 58 additions & 20 deletions Code.gs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ var sourceCalendars = [ // The ics/ical urls that you want to get

];

var howFrequent = 15; // What interval (minutes) to run this script on to check for new events
var howFrequent = 15; // What interval (minutes) to run this script on to check for new events. Any integer can be used, but will be rounded up to 5, 10, 15, 30 or to the nearest hour after that.. 60, 120, etc. 1440 (24 hours) is the maximum value. Anything above that will be replaced with 1440.
var onlyFutureEvents = false; // If you turn this to "true", past events will not be synced (this will also removed past events from the target calendar if removeEventsFromCalendar is true)
var addEventsToCalendar = true; // If you turn this to "false", you can check the log (View > Logs) to make sure your events are being read correctly before turning this on
var modifyExistingEvents = true; // If you turn this to "false", any event in the feed that was modified after being added to the calendar will not update
Expand All @@ -49,6 +49,8 @@ var addTasks = false;

var emailSummary = false; // Will email you when an event is added/modified/removed to your calendar
var email = ""; // OPTIONAL: If "emailSummary" is set to true or you want to receive update notifications, you will need to provide your email address
var customEmailSubject = ""; // OPTIONAL: If you want to change the email subject, provide a custom one here. Default: "GAS-ICS-Sync Execution Summary"
var dateFormat = "YYYY-MM-DD" // date format in the email summary (e.g. "YYYY-MM-DD", "DD.MM.YYYY", "MM/DD/YYYY". separators are ".", "-" and "/")

/*
*=========================================
Expand Down Expand Up @@ -97,16 +99,30 @@ var email = ""; // OPTIONAL: If "emailSummary" is set

var defaultMaxRetries = 10; // Maximum number of retries for api functions (with exponential backoff)

function install(){
//Delete any already existing triggers so we don't create excessive triggers
function install() {
// Delete any already existing triggers so we don't create excessive triggers
deleteAllTriggers();

//Schedule sync routine to explicitly repeat and schedule the initial sync
ScriptApp.newTrigger("startSync").timeBased().everyMinutes(getValidTriggerFrequency(howFrequent)).create();
// Schedule sync routine to explicitly repeat and schedule the initial sync
var adjustedMinutes = getValidTriggerFrequency(howFrequent);
if (adjustedMinutes >= 60) {
ScriptApp.newTrigger("startSync")
.timeBased()
.everyHours(adjustedMinutes / 60)
.create();
} else {
ScriptApp.newTrigger("startSync")
.timeBased()
.everyMinutes(adjustedMinutes)
.create();
}
ScriptApp.newTrigger("startSync").timeBased().after(1000).create();

//Schedule sync routine to look for update once per day
ScriptApp.newTrigger("checkForUpdate").timeBased().everyDays(1).create();
// Schedule sync routine to look for update once per day using everyDays
ScriptApp.newTrigger("checkForUpdate")
.timeBased()
.everyDays(1)
.create();
}

function uninstall(){
Expand Down Expand Up @@ -136,46 +152,66 @@ function startSync(){
}

PropertiesService.getUserProperties().setProperty('LastRun', new Date().getTime());

var currentDate = new Date();
if (onlyFutureEvents)
startUpdateTime = new ICAL.Time.fromJSDate(new Date());
startUpdateTime = new ICAL.Time.fromJSDate(new Date(currentDate.setDate(currentDate.getDate() - getPastDaysIfOnlyFutureEvents)));

//Disable email notification if no mail adress is provided
emailSummary = emailSummary && email != "";

sourceCalendars = condenseCalendarMap(sourceCalendars);
for (var calendar of sourceCalendars){
//------------------------ Reset globals ------------------------
var sourceURL = calendar[0];
var sourceCalendarName = calendar[1];
var targetCalendarName = calendar[2];
var color = calendar[3];
calendarEvents = [];
calendarEventsIds = [];
icsEventsIds = [];
calendarEventsMD5s = [];
recurringEvents = [];

targetCalendarName = calendar[0];
var sourceCalendarURLs = calendar[1];
var vevents;

//------------------------ Determine whether to sync each calendar based on SyncDelay ------------------------
let sourceSyncDelay = Number(calendar[4])*60*1000;
let currentTime = Number(new Date().getTime());
let lastSyncTime = Number(PropertiesService.getUserProperties().getProperty(sourceCalendarName));
var lastSyncDelta = currentTime - lastSyncTime;

if (isNaN(sourceSyncDelay)) {
Logger.log("Syncing " + sourceCalendarName + " because no SyncDelay defined.");
} else if (lastSyncDelta >= sourceSyncDelay) {
Logger.log("Syncing " + sourceCalendarName + " because lastSyncDelta ("+ (lastSyncDelta/60/1000).toFixed(1) + ") is greater than sourceSyncDelay (" + (sourceSyncDelay/60/1000).toFixed(0) + ").");
} else if (lastSyncDelta < sourceSyncDelay) {
Logger.log("Skipping " + sourceCalendarName + " because lastSyncDelta ("+ (lastSyncDelta/60/1000).toFixed(1) + ") is less than sourceSyncDelay (" + (sourceSyncDelay/60/1000).toFixed(0) + ").");
continue;
}

//------------------------ Fetch URL items ------------------------
var responses = fetchSourceCalendars(sourceCalendarURLs);
Logger.log("Syncing " + responses.length + " calendars to " + targetCalendarName);
var responses = fetchSourceCalendars([[sourceURL, color]]);
//Skip the source calendar if a 5xx or 4xx error is returned. This prevents deleting all of the existing entries if the URL call fails.
if (responses.length == 0){
Logger.log("Error Syncing " + sourceCalendarName + ". Skipping...");
continue;
}
Logger.log("Syncing " + sourceCalendarName + " calendar to " + targetCalendarName);

//------------------------ Get target calendar information------------------------
var targetCalendar = setupTargetCalendar(targetCalendarName);
targetCalendarId = targetCalendar.id;
Logger.log("Working on calendar: " + targetCalendarId);
Logger.log("Working on target calendar: " + targetCalendarId);

//------------------------ Parse existing events --------------------------
if(addEventsToCalendar || modifyExistingEvents || removeEventsFromCalendar){
var eventList =
callWithBackoff(function(){
return Calendar.Events.list(targetCalendarId, {showDeleted: false, privateExtendedProperty: "fromGAS=true", maxResults: 2500});
return Calendar.Events.list(targetCalendarId, {showDeleted: false, privateExtendedProperty: 'fromGAS=' + sourceCalendarName, maxResults: 2500});
}, defaultMaxRetries);
calendarEvents = [].concat(calendarEvents, eventList.items);
//loop until we received all events
while(typeof eventList.nextPageToken !== 'undefined'){
eventList = callWithBackoff(function(){
return Calendar.Events.list(targetCalendarId, {showDeleted: false, privateExtendedProperty: "fromGAS=true", maxResults: 2500, pageToken: eventList.nextPageToken});
return Calendar.Events.list(targetCalendarId, {showDeleted: false, privateExtendedProperty: 'fromGAS=' + sourceCalendarName, maxResults: 2500, pageToken: eventList.nextPageToken});
}, defaultMaxRetries);

if (eventList != null)
Expand Down Expand Up @@ -203,7 +239,7 @@ function startSync(){
}, defaultMaxRetries);

vevents.forEach(function(e){
processEvent(e, calendarTz);
processEvent(e, calendarTz, targetCalendarId, sourceCalendarName);
});

Logger.log("Done processing events");
Expand All @@ -212,7 +248,7 @@ function startSync(){
//------------------------ Remove old events from calendar ------------------------
if(removeEventsFromCalendar){
Logger.log("Checking " + calendarEvents.length + " events for removal");
processEventCleanup();
processEventCleanup(sourceURL);
Logger.log("Done checking events for removal");
}

Expand All @@ -226,6 +262,8 @@ function startSync(){
for (var recEvent of recurringEvents){
processEventInstance(recEvent);
}
//Set last sync time for given sourceCalendar
PropertiesService.getUserProperties().setProperty(sourceCalendarName, new Date().getTime());
}

if ((addedEvents.length + modifiedEvents.length + removedEvents.length) > 0 && emailSummary){
Expand Down
Loading